2019 上海网络赛 stone game DP

题目要求 从总石头堆中选取若干个石头为一堆,满足这堆石头大于等于剩下的石头和,且任意拿走一个石头都会小于等于剩下的。

仔细想想就可以知道,只要这堆石头的最小值满足要求,那么该堆石头肯定是符合要求的。 所以所有的状态都和最小值的石头有关

 

dp[j] 表示当前揹包容量为j时 满足要求的个数。dp[j] = dp[j] + dp[j - a[i]] ,a[i]为当前石头的最小值。 a[i] 是确定的,只与j - a[i]有关

 

#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <bitset>
#define  LL long long
#define  ULL unsigned long long
#define mod 1000000007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
using namespace std;
const int maxn = 5e5 + 5;
int a[maxn];
LL dp[maxn];
int sum;
LL ans;
int n;
void slove()
{
  dp[0] = 1;ans = 0;
    for(int i = n - 1; i >= 0; i--){
    int k = a[i];
    for(int j = sum; j >= a[i]; j--){
      if(j >= (sum + 1) / 2 && j * 2 <= sum + a[i])
        ans = (ans + dp[j - a[i]]) % mod;
    dp[j] = (dp[j] + dp[j - a[i]]) % mod;

    }
  }
}
int main()
{
   int T;
   scanf("%d",&T);
   while(T--){
     sum = 0;
     scanf("%d",&n);
     for(int i = 0; i < n; i++){
        scanf("%d",&a[i]);
        sum += a[i];
     }
     sort(a,a + n);
     mem(dp,0);
     slove();
     printf("%lld\n",ans);
   }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章