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);
   }
}

 

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