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
题目传送门:
题目大意:
给你一个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
题目传送门:
题目大意:
给你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
题目传送门:
题目大意:
给你两个字符串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;
}