题目大意:
给出n个水柜,每个水柜初始有一些水,每个水柜都可以装无限大的水。
有一个勺子,勺子的最大容量为k
用勺子舀水有以下规则:
不能从多个水柜中舀水,倒水时也必须一次性倒完,不能剩余
每一次装下的水为min(v,k)其中v为该水柜剩余水量
现在需要使其中一个水柜中的水恰好为V,求是否有一种舀水方案能够满足,若不能,输出“NO”,若能,输出“YES”,并且输出任意一种舀水方案
输出规则为3个数,分别为cnt,x,y表示从x向y中舀cnt次水。
并且,你所输出的方案行数必须不超过n+5
分析:
其实是一道很简单的背包模型,很容易发现,对于每个水柜,我们可以取到与k不同的值为
aimod k
a
i
m
o
d
k
,这样我们就可以得到一个DP式
DP[i]=max(DP[(i−aj)mod k]),其中DP[0]=1
D
P
[
i
]
=
m
a
x
(
D
P
[
(
i
−
a
j
)
m
o
d
k
]
)
,
其
中
D
P
[
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);
}
}
else
PF("NO");
}