上海 2019 J
首先由题意可得,在A'中取走任意t可以使得A'-t <= A 而 A' >= A-A',即在A'中取走最小的石子
先做出01背包找出没有题意限制的可能性
然后退背包,将最小的石子堆从A'的可能性里去除得到了 以 这个最小的石子为最小的所有A'的可能性
#include <cstdio> #include <cmath> #include <algorithm> typedef long long ll; using namespace std; const ll mod = 1e9+7; const int maxn = 300; const int maxm = 500; int dp[maxn*maxm+10]; int a[maxn]; int main () { int t, n; scanf("%d", &t); while (t--) { scanf("%d", &n); int s = 0; for (int i = 0; i < n; i++) scanf("%d", &a[i]), s += a[i]; sort(a, a+n); for (int i = 0; i <= s; i++) dp[i] = 0; dp[0] = 1; for (int i = 0; i < n; i++) { for (int j = s; j >= a[i]; j--) { dp[j] += dp[j-a[i]]; dp[j] %= mod; } }//01背包 ll ans = 0; for (int i = 0; i < n; i++){ //从小到大退背包. 认为最小的石子 t 不断更新为a[i] for (int j = a[i]; j <= s; j++) dp[j] = (dp[j] - dp[j-a[i]] + mod) % mod; //枚举A'-t for (int j = max((s+1)/2-a[i], 0); j <= s-j-a[i]; j++) ans = (ans+dp[j]) % mod; } printf("%lld\n", ans); } return 0; }