題目要求 從總石頭堆中選取若干個石頭爲一堆,滿足這堆石頭大於等於剩下的石頭和,且任意拿走一個石頭都會小於等於剩下的。
仔細想想就可以知道,只要這堆石頭的最小值滿足要求,那麼該堆石頭肯定是符合要求的。 所以所有的狀態都和最小值的石頭有關
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);
}
}