2 条题解

  • 0
    @ 2026-2-27 9:23:04
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const double pi=acos(-1);
    int r[600010];
    void FFT(complex<double> a[],ll n,int op){
    	for(int i=0;i<n;i++)if(i<r[i])swap(a[i],a[r[i]]);
    	for(int m=2;m<=n;m<<=1){
    		complex<double> w1={cos(2*pi/m),sin(2*pi/m)*op};
    		for(int i=0;i<n;i+=m){
    			complex<double> wk=1;
    			for(int j=0;j<m/2;j++){
    				complex<double> x=a[i+j],y=a[i+j+m/2]*wk;
    				a[i+j]=(x+y);
    				a[i+j+m/2]=(x-y);
    				wk=wk*w1; 
    			}
    		}
    	}
    }
    complex<double> a[600010],b[600010],c[600010],ans[600010];
    int main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);
    	int n;
    	cin>>n;
    	ll mx=0;
    	for(int i=0;i<n;i++){
    		ll x;
    		cin>>x;
    		a[x]={1,0};b[x*2]={1,0};c[x*3]={1,0};
    		mx=max(mx,x*3);
    	} 
    	int m=1;
    	while(m<=mx)m<<=1;
    	for(int i=0;i<m;i++)r[i]=r[i/2]/2+(i&1)*m/2;
    	FFT(a,m,1);FFT(b,m,1);FFT(c,m,1);
    	for(int i=0;i<m;i++){
            ans[i]=a[i];
    		ans[i]=ans[i]+(a[i]*a[i]-b[i])*0.5;
    		ans[i]=ans[i]+(a[i]*a[i]*a[i]-b[i]*a[i]*3.0+c[i]*2.0)*(1.0/6.0);
    	}
    	FFT(ans,m,-1);
    	for(int i=0;i<m;i++){
    		ll p=ans[i].real()/m+0.5;
    		if(p)cout<<i<<" "<<p<<'\n';
    	}
    	return 0;
    }
    
    • 0
      @ 2026-1-31 9:45:08
      #include<cstdio>
      #include<cstring>
      #include<cmath>
      using namespace std;
      template<typename hyy>void swap(hyy &a,hyy &b){hyy c=a;a=b;b=c;}
      const int N=1<<20;
      const double Pi=acos(-1);
      int n,m;
      struct CP
      {
          double x,y;
          CP (double xx=0,double yy=0){x=xx;y=yy;}//一个玄学的构造函数 
          CP operator+(CP const&B)const{return CP(x+B.x,y+B.y);}
          CP operator-(CP const&B)const{return CP(x-B.x,y-B.y);}
          CP operator*(CP const&B)const{return CP(x*B.x-y*B.y,x*B.y+B.x*y);}
      }c[N];
      int rev[N];
      void fft(CP *f,int op)
      {
          for(int i=0;i<n;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
          for(int p=2;p<=n;p<<=1)
          {
              int len=p>>1;
              CP DB(cos(2*Pi/p),sin(2*Pi/p));
              DB.y*=op;
              for(int k=0;k<n;k+=p)
              {
                  CP buf(1,0);
                  for(int l=k;l<k+len;l++)
                  {
                      CP tmp=buf*f[l+len];
                      f[l+len]=f[l]-tmp;
                      f[l]=f[l]+tmp;
                      buf=buf*DB;
                  }
              }
          }
      }
      int a[N],p[N],ans[N];
      //PS:看题,升序的,a[i]要么0要么1,不要像我一样看错题,搞半天 
      int main()
      {
          scanf("%d",&n);
          for(int i=1,x;i<=n;i++){scanf("%d",&x);a[x]++;m=x;}m<<=2;
          for(int i=1;i<=m;i++)
          {
              c[i].x=(double)a[i];
              c[i].y=(double)a[i];
          }
          for(n=1;n<=m;n<<=1);
          for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)?(n>>1):0);
          fft(c,1);
          for(int i=0;i<n;i++)c[i]=c[i]*c[i];
          fft(c,-1);
          for(int i=1;i<=m;i++)p[i]=(int)(c[i].y/n/2+0.499);
          for(int i=1;i<=m;i++)
          {
              ans[i*2]-=a[i];//a*a的方案不可选 
              ans[i]+=p[i];ans[i]/=2;//去重(交叉a*b=b*a) 
              ans[i]+=a[i];//加上选一个的方案 
          }//1,2的方案数 
           
          memset(c,0,sizeof(c));//下面计算选3个不同数的方案 
          for(int i=1;i<=m;i++)
          {
              c[i].x=(double)a[i];
              c[i].y=(double)a[i];
          }
          fft(c,1);
          for(int i=0;i<n;i++)c[i]=c[i]*c[i]*c[i];//3次幂 
          fft(c,-1);
          for(int i=1;i<=m;i++)p[i]=(int)(c[i].y/n/2+0.499);
           
          /*
          我们现在有一个多项式的3次幂 
          我们要去掉[1,1,1];[1,1,2]这样的东西 
          [1,1,1]只出现1次 
          本质与[1,1,2]相同的出现3次 
          剩下的情况为合法情况,即3个数互不相同,出现了----6次(全排列) 
          那么我使用一种奇怪的方法去重 
          将[1,1,1]这样的东西算3次,即多算2次 
          然后每个位置就都除上3 
          那么我们不合法的情况就刚好是每个1次,合法的则为2次 
          我们减掉不合法的情况,将剩下的东西的一半计入ans 
          这个不合法的情况怎么减呢 
          我们发现,不合法的情况为两个相同数的乘积乘上任意一个数 
          所以造个多项式A,A=a[1]^2+a[2]^2+a[3]^2+...因为是多项式乘积,所以下标是两倍 
          在来个多项式B,就是原来的多项式,两个一乘,就能算出每个位置的不合法情况数目 
          */
          for(int i=1;i<=m>>2;i++)p[i*3]+=a[i]*2;//这里是3个数都相同,我们给它乘个3,但这个项有额外值,所以是加a[i]*2而不是乘 
          for(int i=1;i<=m;i++)p[i]/=3;
           
          memset(c,0,sizeof(c));
          for(int i=1;i<=m>>2;i++)
          {
              c[i*2].x=(double)a[i];//注意下标2倍 
              c[i].y=(double)a[i];//原来的项 
          }
          fft(c,1);
          for(int i=0;i<n;i++)c[i]=c[i]*c[i];//两个乘一下就是3个数的组合 
          fft(c,-1);
          for(int i=1;i<=m;i++)p[i]-=(int)(c[i].y/n/2+0.499);
          for(int i=1;i<=m;i++)
          {
              int t=ans[i]+p[i]/2;//合法情况算了2次,除回来 
              if(t)printf("%d %d\n",i,t);
          }
          return 0;
      }
      
      • 1

      信息

      ID
      5436
      时间
      1000ms
      内存
      128MiB
      难度
      10
      标签
      递交数
      2
      已通过
      2
      上传者