Codeforces920D-Tanks

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:

 原题目描述在最下面。
 大意:n个坦克,每个坦克容量为a[i],一个勺子容量为k,目标容量为V
 问能否得到一个容量为V的坦克。勺子最多只能转移容量为k的水,若剩余水量不足k,则全部转移。

思路:

 首先这题只需要关心有没有一些坦克容量和sumV同余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;
}


原题目描述;

这里写图片描述

扫描二维码关注公众号,回复: 2227281 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81101086
920
今日推荐