codeforces 286E Ladies' Shop

题目大意:n个小于等于m的数,现在你需要在[1,m]中选择若干个数,使得选出的数能组成的所有数正好与n个数相同,给出最少要选多少个数。

题目分析:

结论一:选择的若干个数一定在n个数中。

证明:否则的话不满足“正好”。

结论二:若a,b在由n个数组成的集合中,则a+b(a+b<=m)也在由n个数组成的集合中。

证明:通过归纳法可以证明。

那么我们考虑构造生成函数G(x)=∑ki*xi,其中当由n组成的集合中有数i时ki=1,否则为0。接着将多出的数删除即可。

代码:

#include<bits/stdc++.h>
using namespace std; typedef long long ll; const ll mod = ;
const int gg = ;
const int maxn = ;
int mp[maxn],a[maxn],f[maxn];
int n,m;
int ord[maxn]; int fast_pow(int now,int p){
if(p == ) return ;
if(p == ) return now;
int z = fast_pow(now,p/); z = (1ll*z*z)%mod;
if(p & ){z = (1ll*z*now)%mod;}
return z;
} void fft(int *d,int len,int kind){
for(int i=;i<len;i++) if(ord[i] > i) swap(d[i],d[ord[i]]);
for(int i=;i<len;i<<=){
int wn = fast_pow(gg,(mod-)/(i<<));
if(kind == -) wn = fast_pow(wn,mod-);
for(int j=;j<len;j += (i<<)){
int w = ;
for(int k=;k<i;k++,w=(1ll*w*wn)%mod){
ll x = d[j+k],y = (1ll*w*d[j+k+i])%mod;
d[j+k] = (x+y)%mod; d[j+k+i] = (x-y+mod)%mod;
}
}
}
if(kind == -){
int inv = fast_pow(len,mod-);
for(int i=;i<len;i++) d[i] = (1ll*d[i]*inv)%mod;
}
} void read(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&a[i]),mp[a[i]] = f[a[i]] = ;
} void work(){
int bit = ,len = ;
while(len < m*) bit++,len<<=;
for(int i=;i<len;i++) ord[i] = (ord[i>>]>>) + ((i&)<<bit-);
fft(f,len,);
for(int i=;i<len;i++) f[i] = (1ll*f[i]*f[i])%mod;
fft(f,len,-);
int ans = ;
for(int i=;i<=m;i++){
if(f[i]&&mp[i]) {mp[i] = ;continue;}
if(f[i]){puts("NO");return;}
if(mp[i]) ans++;
}
puts("YES");
printf("%d\n",ans);
for(int i=;i<=m;i++) if(mp[i]) printf("%d ",i);
} int main(){
read();
work();
return ;
}
上一篇:第三方开源动画库EasyAnimation中一个小bug的修复


下一篇:apache启动错误 AH00072: make_sock: could not bind to address [::]:443 windows系统端口/进程查看