2021 Shanghai I,K
I - Steadily Growing Steam
题目大意
有\(n\)张牌,每张牌有价值\(v_i\)和点数\(t_i\),现在你能最多使\(k\)张牌的点数乘\(2\),然后从中取出若干张牌,分成两组,使得两组的点数和相同,问最大的价值是多少。\((1\leq n\leq100,0\leq k\leq n,|v_i|\leq10^9,1\leq t_i\leq13)\)
思路
首先可以想到背包,我们定义\(dp[i][t1][t2][k]\)为取到第\(i\)张牌时,左边的牌堆点数和为\(t1\),右边牌堆的点数和为\(t2\),且亦有\(k\)张牌的点数被乘\(2\)了的情况的最大价值,然后发现这样的数组是开不下的,所以我们可以去掉一维,就变成了\(dp[i][t1-t2][k]\),这样就刚好能开下,不过前面的\(i\)也可以用滚动数组滚掉,然后就轻松\(AC\)了。
代码
#include<bits/stdc++.h>
using namespace std;
long long val[105];
int t[105];
long long dp[105][5205][105];
long long ans=0;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld%d",&val[i],&t[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=5200;j++)
{
for(int l=0;l<=k;l++)
{
if(dp[i-1][j][l])
{
dp[i][j+t[i]][l]=max(dp[i][j+t[i]][l],dp[i-1][j][l]+val[i]);
dp[i][j-t[i]][l]=max(dp[i][j-t[i]][l],dp[i-1][j][l]+val[i]);
if(l<k)dp[i][j+2*t[i]][l+1]=max(dp[i][j+2*t[i]][l+1],dp[i-1][j][l]+val[i]);
if(l<k)dp[i][j-2*t[i]][l+1]=max(dp[i][j-2*t[i]][l+1],dp[i-1][j][l]+val[i]);
dp[i][j][l]=max(dp[i][j][l],dp[i-1][j][l]);
}
}
}
dp[i][2600+t[i]][0]=max(val[i],dp[i][2600+t[i]][0]);
dp[i][2600-t[i]][0]=max(val[i],dp[i][2600-t[i]][0]);
dp[i][2600+2*t[i]][1]=max(val[i],dp[i][2600+2*t[i]][1]);
dp[i][2600-2*t[i]][1]=max(val[i],dp[i][2600-2*t[i]][1]);
}
for(int i=0;i<=k;i++)ans=max(ans,dp[n][2600][i]);
printf("%lld\n",ans);
return 0;
}
/*
4 1
10 1
-5 3
5 1
6 1
*/
K - Circle of Life
题目大意
有一条\(n\)个点的链,每个点最多只能放\(1\),每秒钟每个\(1\)都会消失且它的左边和右边都会出现一个\(1\),两个\(1\)相撞后就会消逝,问能否构造出一种初始的放法使得在\(2\times n\)的时间之内,这条链会变回原来的样子。\((2\leq n\leq123)\)
思路
有一个统一的构造方法,当长度为\(4\)的时候,\(1001\),当长度为\(5\)的时候,\(10001\),在最后加上\(10\)也是不影响的,所以除了\(3\)之外的所有数都是可以被这样构造出来的,然后\(3\)是没有办法构造的,所以这道题就做完了。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int a=0,b=0,c=0;
if(n==3)printf("Unlucky\n");
else
{
if(n&1){b++;n-=5;}
a=n/4;
c=(n%4==2);
for(int i=1;i<=a;i++)printf("1001");
for(int i=1;i<=b;i++)printf("10001");
for(int i=1;i<=c;i++)printf("10");
printf("\n");
}
return 0;
}

浙公网安备 33010602011771号