2019 icpc 上海网络赛 J Stone game(退背包)
题目大意:
有n个不同重量的石头,求有多少种取的方案满足取走的石头的集合A的总重量>=剩余石头的总重,从取走的石头中任意去掉一个后集合A的总重<=之前剩余石头的总重
首先,只要取走集合A中最轻的一个石头满足条件,那么其余的也一定满足。用背包取求解每一个集合总重的方案数,然后运用退背包的思想,枚举最小质量的石头,退去之后求解满足条件的方案数
#include <bits/stdc++.h>
using namespace std;
const int N = 310 * 510;
typedef long long ll;
ll f[N], a[N];
int T, n;
const int mod = 1e9 + 7;
template <class T1>
bool read(T1 & res){
res = 0;
int flag = 0;
char ch;
if ((ch = getchar()) == '-') {
flag = 1;
}
else if(ch >= '0' && ch <= '9') {
res = ch - '0';
}
while ((ch = getchar()) >= '0' && ch <= '9') {
res = res * 10 + (ch - '0');
}
return true;
}
template <class T1, class ... R>
bool read(T1 & a, R & ... b){
if(!read(a))return false;
else read(b...);
}
int main()
{
read(T);
while (T--){
memset(f, 0, sizeof (f));
memset(a, 0, sizeof (a));
read(n);
ll sum = 0;
for (int i = 1; i <= n; i++){
read(a[i]);
sum += a[i];
}
f[0] = 1;
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++){
for (int j = sum; j >= a[i]; j--){
f[j] = f[j] + f[j - a[i]];
f[j] %= mod;
}
}
ll res = 0;
for (int i = 1; i <= n; i++){
for (int j = a[i]; j <= sum; j++){
f[j] -= f[j - a[i]];
f[j] = (f[j] + mod) % mod;
}//退背包
for (int j = 0; j <= sum; j++){
if(j + a[i] >= sum - (j + a[i]) && j <= sum - (j + a[i])){
res += f[j];
res %= mod;
}//判断是否满足条件
}
}
printf("%lld\n", res);
}
return 0;
}
本文来自博客园,作者:correct,转载请注明原文链接:https://www.cnblogs.com/correct/p/12862034.html

浙公网安备 33010602011771号