Codeforces Round #683 (Div. 2)A-D题题解

A. Add Candies

题目传送门:

A. Add Candies

题目大意:

给你一个n,表示1~n的序列。你可以进行m次操作,每次操作需选中一个其中的一个数,第 j 次操作可以让除了被选中的数的其他所有数加 j 。问你如何构造这样的m次操作使得最后所有数都相等,(操作次数不要求最小)。

思路:

只要使所有数变成1+2+3+……n即可。

AC Code

#include<bits/stdc++.h>
using namespace std;
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        int m;
        scanf("%d",&m);
        printf("%d\n",m);
        for(int i=1;i<=m;i++)
            printf("%d ",i);
        printf("\n");
    }
    return 0;
}

B. Numbers Box

题目传送门:

B. Numbers Box

题目大意:

给你一个n*m的矩阵,每个位置有一个数aij,可能是正的也可以是负的。相邻的两个数可以同时乘以-1改变符号。问最后矩阵中所有元素的和最大是多少。

思路:

我们可以先从行考虑,我们发现如果一行中有偶数个负数时,那么这一行全部都可以转化为正数。当这一行有奇数个负数时,会留下一个负数。

然后我们再从列考虑,经过行的操作后我们发现每一行最多都只有一个负数,然后我们可以把这个负数转化到同一列上,然后就可以继续进行上述行的操作。

综上得,我们发现,当矩阵中的负数个数为偶数时,可以全部转化为正数,当负数个数为奇数时,我们只要把abs( aij )最小的那个数作为负数即可,其他全为正数。

AC Code

#include<bits/stdc++.h>
using namespace std;
int a[15][15];
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        int n,m;
        scanf("%d%d",&n,&m);
        int num=0;
        for(int i=1;i<=n;i++)
        {
    
    
            for(int j=1;j<=m;j++)
            {
    
    
                scanf("%d",&a[i][j]);
                if(a[i][j]<=0) num++;
            }
        }
        int sum=0;
        int minn=0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
    
    
            for(int j=1;j<=m;j++)
            {
    
    
                sum=sum+abs(a[i][j]);
                if(abs(a[i][j])<minn) minn=abs(a[i][j]);
            }
        }
        if(num%2==0) printf("%d\n",sum);
        else printf("%d\n",sum-2*minn);
    }
    //system("pause");
    return 0;
}

C. Knapsack

题目传送门:

C. Knapsack

题目大意:

给你n件物品,每一件物品的重量为wi,背包的载重量为W。问你有什么方案可以使,装入背包的物品的重量和在区间[ W / 2(向上取整),W]。如果无解则输出-1。

思路:

遍历每个物品的重量,如果存在一个物品的重量在题目要求的区间之间,那么直接输出即可。如果没有,那么就把wi < W / 2 的物品加入到一个新的数组,然后从大到小排序,按顺序取即可,如果达到要求重量则退出即可。

AC Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10;
LL n,W;
LL w[N];
struct Node
{
    
    
    int idx;
    int wi;
}node[N];
bool cmp(Node a,Node b)
{
    
    
    return a.wi>b.wi;
}
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        scanf("%lld%lld",&n,&W);
        LL k=W/2;
        if(W%2) k++;
        int idx=0;
        for(int i=1;i<=n;i++)
        {
    
    
            scanf("%d",&w[i]);
            if(w[i]>=k&&w[i]<=W)
                idx=i;  
        }
        if(idx)
        {
    
    
            printf("1\n");
            printf("%d\n",idx);
        } 
        else
        {
    
    
            int tot=0;
            for(int i=1;i<=n;i++)
                if(w[i]<k)
                {
    
    
                    node[++tot].wi=w[i];
                    node[tot].idx=i;
                } 
            if(tot==0) printf("-1\n");
            else
            {
    
    
                LL sum=0;
                sort(node+1,node+1+tot,cmp);
                int i;
                for(i=1;i<=tot;i++)
                {
    
    
                    sum=sum+node[i].wi;
                    if(sum>=k) break;
                }
                if(sum<k) printf("-1\n");
                else 
                {
    
    
                    printf("%d\n",i);
                    for(int j=1;j<=i;j++)
                        printf("%d ",node[j].idx);
                    printf("\n");
                }
            }
        }
    }
    //system("pause");
    return 0;
}

D. Catching Cheaters

题目传送门:

D. Catching Cheaters

题目大意:

给你两个字符串A和B,C,D为两个字符串的子串。求4*LCS(C,D)- len( C ) - len( D ) 的最大值。

思路:

一看到最长公共子序列,那么第一个想到的方法肯定是dp。但是4*LCS(C,D)该怎么处理比较好呢。我们可以转化以下式 4 * lcs - lenx- leny = (2 * lcs - lenx) + (2 * lcs - leny),也就是说当最长公共子序列长度加1时,贡献加2即可。

那么也就有了如下的状态转移方程:
if ( a[ i ] == b[ i ] ) f[ i ][ j ] = max( f [ i - 1 ][ j - 1 ] , 0 ) + 2; (负数就直接不需要了)
else f[ i ][ j ] = max( f[ i ][ j - 1 ] , f[ i - 1 ][ j ] ) - 1; (这时最长公共子序列没变,但是子串长度+1,所以需要减去1)。

AC Code

#include<bits/stdc++.h>
using namespace std;
char str1[5001],str2[5001];
int dp[5001][5001];
int main()
{
    
    
    int n,m;
    scanf("%d%d",&n,&m);
    getchar();
    scanf("%s",str1+1);
    scanf("%s",str2+1);
    int res=0;
    for(int i=1;i<=n;i++)
    {
    
    
        for(int j=1;j<=m;j++)
        {
    
    
            if(str1[i]==str2[j])
                dp[i][j]=max(dp[i][j],dp[i-1][j-1]+2);
            else
                dp[i][j]=max(dp[i-1][j]-1,dp[i][j-1]-1);
            res=max(res,dp[i][j]);
            if(dp[i][j]<0) dp[i][j]=0;            
        }
    }
    printf("%d\n",res);
    //system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Stevenwuxu/article/details/109730349