(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题意:
原题目描述在最下面。
大意:n
个坦克,每个坦克容量为a[i]
,一个勺子容量为k
,目标容量为V
。
问能否得到一个容量为V
的坦克。勺子最多只能转移容量为k
的水,若剩余水量不足k
,则全部转移。
思路:
首先这题只需要关心有没有一些坦克容量和sum
和V
同余K
即可。若存在,则一定有解。设这些坦克为组合yes。
状态表示:
dp[i][j]
:表示由前i
辆坦克能否得到容量j mod k
。
is[i][j]
: 表示当dp[i][j]
为真时,第i
辆坦克是否做出贡献,也就是第i
辆坦克是否在yes中。
dp[0][0]
初始化为1.
当dp[n][v%k]
为真时则一定有解。
状态转移方程:
if
dp[i - 1][j]
:
dp[i][j] = 1
dp[i][j + (ar[i])%k] = 1
is[i][j + (ar[i])%k] = 1
构造过程:
构造过程坑很多,看我提交记录就知道了~~
首先把yes组合里的坦克的水全放到第一个坦克中去,建议再把no组合里的坦克的水也放到第一个坦克里。
yes组合水量:sum
当sum > V时:把yes第一个坦克里多余的水移到其他坦克中。
当sum < V时:把no第一个坦克里多余的水移到yes里去。(注意:yes可能为空,这里要稍微处理一下)
详细过程见代码。
AC代码:
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;
const int N = 5e3+7;
const int INF = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
int n, k, v;
int ar[N], dp[N][N], is[N][N];
std::vector<int> yes, no;
int ab(int x){
return x<0?-x:x;
}
int main(int argc, char const *argv[]){
while(~scanf("%d%d%d", &n, &k, &v)){
int flag = 1, sum = 0;
for(int i = 1; i <= n; ++i){
scanf("%d", &ar[i]);
sum += ar[i];
}
if(sum < v){
printf("NO\n");
continue;
}
memset(dp, 0, sizeof(dp));
memset(is, 0, sizeof(is));
dp[0][0] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 0; j < k; ++j){
if(dp[i-1][j] == 0)continue;
dp[i][j] = 1;
dp[i][(j+ar[i])%k] = 1;
is[i][(j+ar[i])%k] = 1;
}
}
int tv = v%k;
if(!dp[n][tv]){
printf("NO\n");
continue;
}
yes.clear();no.clear();
for(int i = n; i >= 1; --i){
if(is[i][tv]){
yes.pb(i);
tv = (tv - (ar[i]%k) + k)%k;
}else no.pb(i);
}
sort(yes.begin(),yes.end());
sort(no.begin(),no.end());
int len = yes.size();sum=0;
printf("YES\n");if(len)sum = ar[yes[0]];
for(int i = 1, tmp; i < len; ++i){
sum += ar[yes[i]];
tmp = ar[yes[i]]/k;
if(ar[yes[i]]%k)tmp++;
if(tmp)printf("%d %d %d\n", tmp, yes[i], yes[0]);
}
int a = 1, b = 1, tmp;
int lenb = no.size();
for(int i = 1, temp; i < lenb; ++i){
temp = ar[no[i]]/k;
if(ar[no[i]]%k)temp++;
if(temp)printf("%d %d %d\n", temp, no[i], no[0]);
}
if(sum > v){
if(len == 0){
printf("**\n");
a = no[0];
b = no[1];
}else{
a = yes[0];
if(len == 1)b = no[0];
else b = yes[1];
}
tmp = (sum - v)/k;
if(tmp == 0)tmp++;
printf("%d %d %d\n", tmp, a, b);
}else if(sum < v){
tmp = (v - sum)/k;
a = no[0];
if(len == 0)b = no[1];
else b = yes[0];
printf("%d %d %d\n", tmp, a, b);
}
}
return 0;
}