当前位置: 代码迷 >> 综合 >> 【DP】Codeforces EDU37 Tanks
  详细解决方案

【DP】Codeforces EDU37 Tanks

热度:100   发布时间:2023-09-27 08:24:17.0

题目大意:

给出n个水柜,每个水柜初始有一些水,每个水柜都可以装无限大的水。
有一个勺子,勺子的最大容量为k
用勺子舀水有以下规则:
不能从多个水柜中舀水,倒水时也必须一次性倒完,不能剩余
每一次装下的水为min(v,k)其中v为该水柜剩余水量
现在需要使其中一个水柜中的水恰好为V,求是否有一种舀水方案能够满足,若不能,输出“NO”,若能,输出“YES”,并且输出任意一种舀水方案
输出规则为3个数,分别为cnt,x,y表示从x向y中舀cnt次水。
并且,你所输出的方案行数必须不超过n+5


分析:

其实是一道很简单的背包模型,很容易发现,对于每个水柜,我们可以取到与k不同的值为aimod kaimodk,这样我们就可以得到一个DP式
DP[i]=max(DP[(i?aj)mod k])DP[0]=1DP[i]=max(DP[(i?aj)modk]),其中DP[0]=1最后我们再将其中多的或少的处理一下即可(都是k的倍数)。
对于所输出方案的行数的要求,其实是没有任何必要的。
我们很容易发现,假设最终有一个合法方案,那么我们可以把每个水柜的值直接移动到最终状态下的位置,那么就可以保证总共输出的行数在n以内了。
另外,对于v%k=0的情况,我们要特殊处理。。其实很简单,把所有的值怼在一块,然后从中选取v就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define SF scanf
#define PF printf
#define MAXN 5010
using namespace std;
int n,k,now,t;
long long a[MAXN],v;
int dp[2][MAXN],fa[2][MAXN];
int get_ans(int x){//PF("[%d %I64d]\n",x,a[fa[now][x]]%k);if(x==a[fa[now][x]]%k)return fa[now][x];int t1=get_ans((x-(a[fa[now][x]]%k)+k)%k);PF("%I64d %d %d\n",a[t1],t1,fa[now][x]);a[fa[now][x]]+=a[t1];a[t1]=0;return fa[now][x];
}
int find_less(){int fir=0;for(int i=1;i<=n;i++)if(a[i]!=0&&i!=t){if(fir!=0){PF("%I64d %d %d\n",a[i],i,fir);a[i]=0;}else{fir=i;}}return fir;
}
int main(){int sum=0;SF("%d%d%I64d",&n,&k,&v);for(int i=1;i<=n;i++){SF("%I64d",&a[i]);sum+=a[i];}if(sum<v){PF("NO");return 0;}if(v%k==0){if(n==1&&a[1]!=v)PF("NO");else{PF("YES\n");if(a[1]!=0)PF("%I64d %d %d\n",a[1],1,2);a[2]+=a[1];a[1]=0;if(v!=0){int t2=find_less();PF("%I64d %d %d",v/k,t2,1);}}return 0;}dp[0][0]=1;now=0;for(int i=1;i<=n;i++){now^=1;int x=a[i]%k;memset(dp[now],0,sizeof dp[now]);for(int j=0;j<=k;j++){if(dp[now^1][j]==1&&dp[now^1][(j+x)%k]==0){dp[now][(j+x)%k]=1;fa[now][(j+x)%k]=i;}if(dp[now^1][j]==1){dp[now][j]=dp[now^1][j];fa[now][j]=fa[now^1][j];}}}if(dp[now][v%k]==1){PF("YES\n");t=get_ans(v%k);//PF("[%d %lld]\n",t,a[t]);if(a[t]>v)PF("%I64d %d %d\n",(a[t]-v)/k,t,t%n+1);else if(a[t]==v){return 0;}else{int t2=find_less();PF("%I64d %d %d\n",(v-a[t])/k,t2,t);}}elsePF("NO");
}