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;
    }
  • 相关阅读:
    移动端解决fixed和input弹出虚拟键盘时样式错位
    JS的面向对象
    js计算两个时间范围间的间隔秒数
    使用js过滤字符串前后的空格
    C#时间格式-摘自http://www.cnblogs.com/xiaogongzhu/p/3825600.html
    [dp/贪心]435. 无重叠区间-----经典问题
    【dp】Leetcode面试题 17.16. 按摩师
    [dp]Leetcode.376.摆动序列
    Leetcode 945 使数组唯一的最小增量
    LeetCode 365.水壶问题
  • 原文地址:https://www.cnblogs.com/1-1-1-1/p/8572193.html
Copyright © 2011-2022 走看看