zoukankan      html  css  js  c++  java
  • 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 = 998244353;
    const int gg = 3;
    const int maxn = 2520210;
    int mp[maxn],a[maxn],f[maxn];
    int n,m;
    int ord[maxn];
    
    int fast_pow(int now,int p){
        if(p == 0) return 1;
        if(p == 1) return now;
        int z = fast_pow(now,p/2); z = (1ll*z*z)%mod;
        if(p & 1){z = (1ll*z*now)%mod;}
        return z;
    }
    
    void fft(int *d,int len,int kind){
        for(int i=0;i<len;i++) if(ord[i] > i) swap(d[i],d[ord[i]]);
        for(int i=1;i<len;i<<=1){
            int wn = fast_pow(gg,(mod-1)/(i<<1));
            if(kind == -1) wn = fast_pow(wn,mod-2);
            for(int j=0;j<len;j += (i<<1)){
                int w = 1;
                for(int k=0;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 == -1){
            int inv = fast_pow(len,mod-2);
            for(int i=0;i<len;i++) d[i] = (1ll*d[i]*inv)%mod;
        }
    }
    
    void read(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]] = f[a[i]] = 1;
    }
    
    void work(){
        int bit = 0,len = 1;
        while(len < m*2) bit++,len<<=1;
        for(int i=1;i<len;i++) ord[i] = (ord[i>>1]>>1) + ((i&1)<<bit-1);
        fft(f,len,1);
        for(int i=0;i<len;i++) f[i] = (1ll*f[i]*f[i])%mod;
        fft(f,len,-1);
        int ans = 0;
        for(int i=0;i<=m;i++){
            if(f[i]&&mp[i]) {mp[i] = 0;continue;}
            if(f[i]){puts("NO");return;}
            if(mp[i]) ans++;
        }
        puts("YES");
        printf("%d
    ",ans);
        for(int i=0;i<=m;i++) if(mp[i]) printf("%d ",i);
    }
    
    int main(){
        read();
        work();
        return 0;
    }
  • 相关阅读:
    【BZOJ3784】树上的路径 点分治序+ST表
    【BZOJ3698】XWW的难题 有上下界的最大流
    【BZOJ2006】[NOI2010]超级钢琴 ST表+堆
    【BZOJ4016】[FJOI2014]最短路径树问题 最短路径树+点分治
    【BZOJ2724】[Violet 6]蒲公英 分块+二分
    【BZOJ3697】采药人的路径 点分治
    【BZOJ4026】dC Loves Number Theory 分解质因数+主席树
    【BZOJ3510】首都 LCT维护子树信息+启发式合并
    Python Web学习笔记之socket编程
    Python Web学习笔记之socket套接字
  • 原文地址:https://www.cnblogs.com/1-1-1-1/p/8572193.html
Copyright © 2011-2022 走看看