Codeforces Round #176 (Div. 1) E. Ladies' Shop(FFT)

版权声明:转载需要注明哦QwQ,地址:http://blog.csdn.net/effervescence。 https://blog.csdn.net/Effervescence/article/details/81460769

题意

  给出一个 n 个数组成的集合,所有的数 m ,之后让你在 1 m 中选出一些数,使得取出这些数中的一些数进行求和可以得出的所有 m 的数与原来的 n 个数组成的集合相同。

分析

  首先我们可以得出,我们选的数必定为给出的集合的子集,不然这个数本身自己就不在原集合中,肯定不满足。接下来我们考虑原集合中的任意两个数 a , b ,如果 a + b m a + b 不在这个集合中的话,那么肯定就无解了,如果 a + b m 并且 a + b 在这个集合中,那么这个 a + b 就可以删去(非常显然)。之后我们考虑一个数 n u m = a 0 + a 1 + . . . + a n ,可以把 n u m 分解为 a 0 , a 1 + . . . + a n ,可以很显然的发现, a 0 a 1 + . . . + a n 也必须在原集合中,于是我们就可以通过生成函数转化一下,构造一个多项式,即 x i 的系数为构造出这个数的方法。那么对于原集合,我们将多项式构造出来后将多项式平方,就可以得出需要的结果了。因为我们可以证明所有集合中的数都可以通过少于两个的数构造出来,那么我们只要一次FFT就可以解决问题了。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int fmaxn=21,Fmaxn=(1<<fmaxn)+1;
const double pi=acos(-1);
struct Complex {
    double Real,Image;
    #define x Real
    #define y Image
    Complex(double x=0,double y=0):x(x),y(y){}
    inline Complex operator + (const Complex &a) const {
        return Complex(x+a.x,y+a.y);
    }
    inline Complex operator - (const Complex &a) const {
        return Complex(x-a.x,y-a.y);
    }
    inline Complex operator * (const Complex &a) const {
        return Complex(x*a.x-y*a.y,x*a.y+y*a.x);
    }
    inline Complex operator * (const double &a) const {
        return Complex(x*a,y*a);
    }
    inline Complex operator / (const double &a) const {
        return Complex(x/a,y/a);
    }
};
namespace Transform {
//  Complex root[fmaxn][Fmaxn];
    int rev[Fmaxn],mx;
    inline void DFT(Complex *a,int n) {
//      if(mx<n) {
//          for(int i=mx;i<n;++i) {
//              int len=1<<i; 
//              for(int j=0;j<len;++j)
//                  root[i][j]=Complex(cos(pi/len*j),sin(pi/len*j));
//          }
//          mx=n;
//      }
        rev[0]=0;
        for(int i=0;i<(1<<n);++i) {
            rev[i]=i&1?rev[i^1]|(1<<(n-1)):rev[i>>1]>>1;
            if(i<rev[i])
                swap(a[i],a[rev[i]]);
        }
        for(int l=0;l<n;++l) {
            int len=(1<<l);
            Complex wn=Complex(cos(2*pi/(len<<1)),sin(2*pi/(len<<1)));
            for(int i=0;i<(1<<n);i+=(len<<1)) {
                Complex w=Complex(1,0);
                for(int j=0;j<len;++j,w=w*wn) {
                    Complex x=a[i+j+len]*w;
                    a[i+j+len]=a[i+j]-x,a[i+j]=a[i+j]+x;
                }
            }
        }
    }
    inline void IDFT(Complex *a,int n) {
        int len=1<<n;
        reverse(a+1,a+len);
        DFT(a,n);
        for(int i=0;i<len;++i)
            a[i]=a[i]/len;
    }
}
int n,m,l;
bool vis[Fmaxn];
Complex a[Fmaxn];
int main(void) {
    read(n),read(m);
    for(int i=1,x;i<=n;i++)
        read(x),vis[x]=1,a[x]=Complex(1,0);
    while((1<<l)<m+m+1)
        l++;
    Transform::DFT(a,l);
    for(int i=0;i<(1<<l);++i)
        a[i]=a[i]*a[i];
    Transform::IDFT(a,l);
//  Transform::FFT(a,a,m,m);
//  Convolution(a,b,lim);
//  for(int i=1;i<=m;++i)
//      cout<<a[i]<<endl;
    vector<int>ans;
    ans.clear();
    for(int i=1;i<=m;++i)
        if(a[i].x<1e-5&&vis[i])
            ans.push_back(i);
        else if(a[i].x>1e-5&&!vis[i])
            return 0*puts("NO");
    printf("YES\n%d\n",ans.size());
    for(int i=0;i<ans.size();++i)
        printf("%d ",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/Effervescence/article/details/81460769
今日推荐