P4799 [CEOI2015 Day2]世界冰球锦标赛
\(0-1\)背包解法
适用数据范围:\(N≤40,M≤10^6\)
状态表示:\(f(i,j)\):从前\(i\)个物品中选,花费不超过(小于等于)\(j\)的方案数。
最后累加\(f(n,0~m)\)即可。
const int N=45,M=1e6+10;
LL price[N];
LL f[M];
LL n,m;
LL ans;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>price[i];
f[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=m;j>=price[i];j--)
{
f[j]+=f[j-price[i]];
}
}
for(int i=0;i<=m;i++) ans+=f[i];
cout<<ans<<endl;
//system("pause");
}
折半搜索——正解
我们可以将所有比赛分成两部分,对这两部分分别进行指数型枚举,然后使用vector来储存搜索过程中产生的可能的花费。
最后再将两部分进行合并,得出最终的答案。
时间复杂度:\(O(2^{\frac{n}{2}}log2^{\frac{n}{2}})\)
const int N=45;
LL price[N];
vector<LL> suml;
vector<LL> sumr;
LL n,m;
LL ans;
void dfs(int l,int r,LL sum,vector<LL> &v)
{
if(l>r)
{
v.pb(sum);
return;
}
if(sum + price[l] <= m) dfs(l+1,r,sum+price[l],v);
dfs(l+1,r,sum,v);
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>price[i];
dfs(0,n/2-1,0,suml);
dfs(n/2,n-1,0,sumr);
sort(suml.begin(),suml.end());
for(int i=0;i<sumr.size();i++)
{
ans+=upper_bound(suml.begin(),suml.end(),m-sumr[i])-suml.begin();
}
cout<<ans<<endl;
//system("pause");
}