2 条题解
-
0
#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
#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
- 上传者