2019 icpc 上海网络赛 J Stone game(退背包)

AC通道 

题目大意:

有n个不同重量的石头,求有多少种取的方案满足取走的石头的集合A的总重量>=剩余石头的总重,从取走的石头中任意去掉一个后集合A的总重<=之前剩余石头的总重

首先,只要取走集合A中最轻的一个石头满足条件,那么其余的也一定满足。用背包取求解每一个集合总重的方案数,然后运用退背包的思想,枚举最小质量的石头,退去之后求解满足条件的方案数

退背包

#include 
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 
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 
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;
}

 

你可能感兴趣的:(DP)