假垃圾
创意 JAG 推荐题目之:假mirage,简称假垃圾。
看到这个唯一可装箱,一个想法是去刻画这个集合长什么样,然而并没有成功。
于是退而求其次,考虑怎么对于确定的子集
我们可以胡出一种贪心:记原来的集合为
接下来我们需要确保这是唯一的方案,也就是不能通过调整得到新方案。考虑在这基础上怎么调整出一个新方案。
从最小的值
也就是若存在
所以不能得到新方案的条件即为
我们可以枚举
这个区间做背包时间复杂度会爆炸,但是注意到元素大小的限制和背包大小的限制是一样的,所以可以直接取后缀做背包,预处理复杂度
然后上面的条件并没有对于
看不懂一堆限制的可以自己推,细节可以看代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5005,mod=998244353;
int n,w,a[N],b[N][N],sum[N][N],pw[N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
pw[0]=1;for(int i=1;i<N;i++) pw[i]=pw[i-1]*2%mod;
cin>>n>>w;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
b[n+1][0]=1;
for(int i=n;i>=1;i--){
memcpy(b[i],b[i+1],sizeof(b[i]));
memcpy(sum[i],sum[i+1],sizeof(sum[i]));
for(int j=w;j>=a[i];j--)
b[i][j]=(b[i][j]+b[i+1][j-a[i]])%mod;
++sum[i][a[i]];
}
for(int i=1;i<=n+1;i++)
for(int j=1;j<=w;j++)
b[i][j]=(b[i][j]+b[i][j-1])%mod,sum[i][j]+=sum[i][j-1];
for(int m=1;m<=w;m++){
ll ans=0;
for(int j=1;j<=n&&a[j]<=m;j++){
int num=sum[j+1][m]-sum[j+1][m-a[j]];
ans=(ans+1ll*b[j+1][m-a[j]]*pw[num])%mod;
}
cout<<ans<<' ';
}
return 0;
}
好了题解结束,谢谢观看。