链接
https://nanti.jisuanke.com/t/41420
题意
n n n 堆石子,每堆石子都有重量 w w w
设 S ′ S' S′ 是取的石子的重量 , S S S 是石子总重量
求满足 ( S ′ ≥ S − S ′ ) ⋀ ( ∀ t ∈ S ′ , S ′ − t ≤ S − S ′ ) (S' \ge S-S') \bigwedge (\forall t\in S',S'−t \le S−S') (S′≥S−S′)⋀(∀t∈S′,S′−t≤S−S′) 的方案数
思路
01 背包退背包
当 a ( a ∈ S ′ ) a(a\in S') a(a∈S′) 为最小值
如果 S ′ − a ≤ S − S ′ S′−a\le S−S′ S′−a≤S−S′ 成立
那么 ∀ t ∈ S ′ , S ′ − t ≤ S − S ′ \forall t\in S′,S′−t\le S−S′ ∀t∈S′,S′−t≤S−S′ 恒成立
先算 01 0 1 01 背包方案数
再从小到大进行退背包,并判断是否符合不等式
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n,w[305];
ll f[150005];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--) {
cin>>n;
int s=0;
for(int i=1;i<=n;i++) cin>>w[i],s+=w[i];
sort(w+1,w+1+n);
memset(f,0,sizeof f);
f[0]=1;
for(int i=1;i<=n;i++)
for(int j=s;j>=w[i];j--)
f[j]=(f[j]+f[j-w[i]])%mod;
ll ans=0;
for(int i=1;i<=n;i++) {
for(int j=w[i];j<=s;j++) f[j]=(f[j]-f[j-w[i]]+mod)%mod;
for(int j=w[i];j<=s;j++)
if(j>=s-j&&j-w[i]<=s-j)
ans=(ans+f[j-w[i]])%mod;
}
cout<<ans<<endl;
}
return 0;
}