@ivorysi
2018-01-02T08:57:28.000000Z
字数 11440
阅读 807
笔记
给出n个数qi,给出Fj的定义如下:
令Ei=Fi/qi,求Ei.
第一行一个整数n。
接下来n行每行输入一个数,第i行表示qi。
n≤100000,0
n行,第i行输出Ei。与标准答案误差不超过1e-2即可。
5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880
-16838672.693
3439.793
7509018.566
4595686.886
10903040.872
我们发现实际上就是
对应位置的系数
减去
相反位置的系数
用FFT优化卷积
有一点没想通就是为什么他们都把数组长度做n*2然后再扩展次数界
才反应过来……乘法后的数字长度不是最多往后扩展两倍吗……多项式乘法最大不就最高次项指数翻一番吗……所以次数界最小不就要比n*2还要大吗
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 400005#define ivorysiusing namespace std;typedef long long ll;struct complex {double r,i;complex(double real=0.0,double image=0.0) {r=real;i=image;}complex operator + (const complex &rhs) {return complex(r+rhs.r,i+rhs.i);}complex operator - (const complex &rhs) {return complex(r-rhs.r,i-rhs.i);}complex operator * (const complex &rhs) {return complex(r*rhs.r-i*rhs.i,r*rhs.i+i*rhs.r);}};const double PI=acos(-1.0);void brc(complex *p,int l) {int j=l/2;for(int i=1;i<l-1;++i) {if(i<j) swap(p[i],p[j]);int k=l/2;while(j>=k) {j-=k;k>>=1;}j+=k;}}void FFT(complex *p,int l,int on) {brc(p,l);complex u,t;for(int h=2;h<=l;h<<=1) {complex wn=complex(cos(on*2*PI/h),sin(on*2*PI/h));for(int k=0;k<l;k+=h) {complex w=complex(1.0,0);for(int j=k;j<k+h/2;++j) {u=p[j];t=w*p[j+h/2];p[j]=u+t;p[j+h/2]=u-t;w=w*wn;}}}}int n;complex f[MAXN],f_rev[MAXN],g[MAXN],ans1[MAXN],ans2[MAXN];int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifscanf("%d",&n);--n;siji(i,0,n) {scanf("%lf",&f[i].r);f_rev[n-i]=f[i];}siji(i,1,n) {g[i].r=1.0/i/i;}int l=1;while(l-1<n*2) {l<<=1;}FFT(f,l,1);FFT(f_rev,l,1);FFT(g,l,1);xiaosiji(i,0,l) {ans1[i]=f[i]*g[i];ans2[i]=f_rev[i]*g[i];}FFT(ans1,l,-1);FFT(ans2,l,-1);xiaosiji(i,0,l) ans1[i].r/=l,ans2[i].r/=l;siji(i,0,n) {printf("%.3lf\n",ans1[i].r-ans2[n-i].r);}return 0;}
我们讲一个悲伤的故事。
从前有一个贫穷的樵夫在河边砍柴。
这时候河里出现了一个水神,夺过了他的斧头,说:
“这把斧头,是不是你的?”
樵夫一看:“是啊是啊!”
水神把斧头扔在一边,又拿起一个东西问:
“这把斧头,是不是你的?”
樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”
水神又把手上的东西扔在一边,拿起第三个东西问:
“这把斧头,是不是你的?”
樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。
于是他又一次答:“是啊是啊!真的是!”
水神看着他,哈哈大笑道:
“你看看你现在的样子,真是丑陋!”
之后就消失了。
樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。
于是他准备回家换一把斧头。
回家之后他才发现真正坑爹的事情才刚开始。
水神拿着的的确是他的斧头。
但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。
换句话说,水神可能拿走了他的一把,两把或者三把斧头。
樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。
他想统计他的损失。
樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。
他想对于每个可能的总损失,计算有几种可能的方案。
注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。
第一行是整数N,表示有N把斧头。
接下来n行升序输入N个数字Ai,表示每把斧头的价值。
若干行,按升序对于所有可能的总损失输出一行x y,x为损失值,y为方案数。
4
4
5
6
7
4 1
5 1
6 1
7 1
9 1
10 1
11 2
12 1
13 1
15 1
16 1
17 1
18 1
11有两种方案是4+7和5+6,其他损失值都有唯一方案,例如4=4,5=5,10=4+6,18=5+6+7.
所有数据满足:Ai<=40000
我FFT写出了一个很蠢的错误!把h写成了l……
这道题用fft,就是复杂化加法,因为我们知道,两个数相乘,指数相加
然后用a表示一个数的多项式,b表示两个相同的数搭配起来的值的多项式,c表示3个相同的数搭配出来的多项式
两把斧子的搭配方式 (a*a-b)/2
三把斧子搭配方式 (a*a*a-a*b*3+c*2)/6
用的是容斥原理
【打倒资本主义河神】
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 40005//#define ivorysiusing namespace std;typedef long long ll;struct complex {double r,i;complex(double real=0.0,double image=0.0) {r=real;i=image;}friend complex operator +(const complex &a,const complex &b) {return complex(a.r+b.r,a.i+b.i);}friend complex operator -(const complex &a,const complex &b) {return complex(a.r-b.r,a.i-b.i);}friend complex operator *(const complex &a,const complex &b) {return complex(a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r);}}a[MAXN*4],b[MAXN*4],c[MAXN*4],e2[MAXN*4],e3[MAXN*4];const double PI=acos(-1.0);ll ans[MAXN*4];int tot,n;void brc(complex *p,int l) {int j=l/2;xiaosiji(i,1,l-1) {if(i<j) swap(p[i],p[j]);int k=l/2;while(j>=k) {j-=k;k>>=1;}j+=k;}}void FFT(complex *p,int l,int on) {brc(p,l);complex u,t;for(int h=2;h<=l;h<<=1) {complex wn(cos(on*2*PI/h),sin(on*2*PI/h));for(int k=0;k<l;k+=h) {complex w(1.0,0);for(int j=k;j<k+h/2;++j) {u=p[j];t=w*p[j+h/2];p[j]=u+t;p[j+h/2]=u-t;w=w*wn;}}}if(on==-1) {xiaosiji(i,0,l) p[i].r/=l;}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifscanf("%d",&n);int x;siji(i,1,n) {scanf("%d",&x);ans[x]++;tot=max(tot,x);a[x].r=1.0;b[2*x].r=1.0;c[3*x].r=1.0;}int l=1;while(l-1<3*tot) l<<=1;FFT(a,l,1);FFT(b,l,1);FFT(c,l,1);xiaosiji(i,0,l) {e2[i]=(a[i]*a[i]-b[i])*complex(1.0/2.0,0);e3[i]=(a[i]*a[i]*a[i]-a[i]*b[i]*complex(3,0)+c[i]*complex(2,0))*complex(1.0/6.0,0);}FFT(e2,l,-1);FFT(e3,l,-1);xiaosiji(i,0,l) {ans[i]+=(ll)(e2[i].r+0.5);ans[i]+=(ll)(e3[i].r+0.5);if(ans[i]!=0) {printf("%d %d\n",i,ans[i]);}}return 0;}
给定一个长度为N的数组A[],求有多少对i, j, k(1<=i
第一行一个整数N(N<=10^5)。
接下来一行N个数A[i](A[i]<=30000)。
一行一个整数。
10
3 5 3 6 3 4 10 4 5 2
9
fft运算的数组开四倍!
这道题可以很容易想到一个用FFT暴力的思路,枚举中间点,两边用卷积快速算一下,复杂度是显然超时
然后很神奇的是我们可以用空间换时间,这种方法就是分块
我们把这n个数分成个为一块,一共有块,额外开数组记下每个块中数出现的次数,对于一个点,在如果i,k在块内都可以通过预处理的数值计算出来
例如当前块的编号是id,我们要记录块[1,id-1]之间每个数字出现的个数,块[id+1,tot]之间每个数的个数,然后块里排在它之前每个数出现的个数,当前数字编号为p,枚举块内除了p以外所有点进行转移
这样有什么好处呢,假如i和k都不在块内我们才需要卷积,这样可以降低卷积的次数,也就是说,卷积的次数减少到了块的个数
那么复杂度就变成了
这里最影响复杂度的算是了,大概可以支持S到2000左右,如果S是根号n的话会超时
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 100005//#define ivorysiusing namespace std;typedef long long ll;struct complex {double r,i;complex(double real=0.0,double image=0.0) {r=real;i=image;}friend complex operator +(const complex &a,const complex &b) {return complex(a.r+b.r,a.i+b.i);}friend complex operator -(const complex &a,const complex &b) {return complex(a.r-b.r,a.i-b.i);}friend complex operator *(const complex &a,const complex &b) {return complex(a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r);}}Lnum[200005],Rnum[200005],match[200005];const double PI=acos(-1.0);void brc(complex *p,int l) {int j=l/2;xiaosiji(i,1,l-1) {if(i<j) swap(p[i],p[j]);int k=l/2;while(j>=k) {j-=k;k>>=1;}j+=k;}}void FFT(complex *p,int l,int on) {brc(p,l);complex u,t;for(int h=2;h<=l;h<<=1) {complex wn(cos(on*2*PI/h),sin(on*2*PI/h));for(int k=0;k<l;k+=h) {complex w(1.0,0);for(int j=k;j<k+h/2;++j) {u=p[j];t=w*p[j+h/2];p[j]=u+t;p[j+h/2]=u-t;w=w*wn;}}}if(on==-1) {xiaosiji(i,0,l) p[i].r/=l;}}ll ans;int n,a[MAXN],lim,Lz;int R[200005],L[200005],cnt[60005][350],cnt_pre[60005];int bl[350],br[350],tot,S;void Block_Init() {S=1000;xiaosiji(i,0,n) {if(i%S==0) br[tot]=i-1,bl[++tot]=i;}br[tot]=n-1;siji(i,1,tot) {siji(j,bl[i],br[i]) {cnt[a[j]][i]++;}}}void calc(int p) {int id=p/S+1;siji(j,bl[id],p-1) {if(2*a[p]>=a[j]) ans+=R[2*a[p]-a[j]];}siji(j,p+1,br[id]) {if(2*a[p]>=a[j]) ans+=L[2*a[p]-a[j]]+cnt_pre[2*a[p]-a[j]];}if(p==0 || p==n-1) return;ans+=(ll)(match[2*a[p]].r+0.5);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifscanf("%d",&n);xiaosiji(i,0,n) {scanf("%d",&a[i]);lim=max(lim,a[i]);R[a[i]]++;}Block_Init();Lz=1;while(Lz-1<2*lim) Lz<<=1;siji(i,1,tot) {siji(j,0,lim) {R[j]-=cnt[j][i];cnt_pre[j]=0;}if(i!=1 || i!=tot) {siji(j,0,Lz) {Lnum[j]=complex(L[j],0);Rnum[j]=complex(R[j],0);}FFT(Lnum,Lz,1);FFT(Rnum,Lz,1);xiaosiji(j,0,Lz) {match[j]=Lnum[j]*Rnum[j];}FFT(match,Lz,-1);}siji(j,bl[i],br[i]) {calc(j);++cnt_pre[a[j]];}siji(j,0,lim) {L[j]+=cnt[j][i];}}printf("%lld\n",ans);return 0;}
刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.
仅一行一个整数n(<=130000)
仅一行一个整数, 为方案数 mod 1004535809.
3
4
这道题的质数比较神奇是
然后2^n还正好比n要大
然后我们进行神奇的,多项式求逆元
首先求逆元的式子是
我们要求
假如我们求好了
然后去求
为什么模数换了还成立啊……因为当然是的约数啊
然后后两个式子相减
我们把两边平方
为什么平方还成立啊
因为平方以前里面式子的每个项前面的系数都是0
平方以后i和k-i必然有一个东西是小于的
所以平方后还成立
然后式子两边乘上
然后用FNT加速一下这个东西就好了
然后再说FNT是个什么鬼
因为我们的FFT只能满足在复数领域随便的乱搞,万一有了取模呢……然后就会变得特别的烦人
对于这道题,模数是一个非常神奇的东西,也就是说是,它还是个质数
同时这个
假如2×n的次数界就是的话
然后对于质数我们求它的原根(这道题的原根是3),原根和单位复根比较像,转到很多个不同的值后,根据费马小定理,还能会到1
令这样保证了,同时还使这一圈取值各不相同,和单位复根的性质是一样的
然后我们就把当成单位复根做FFT就好,实际上还是很简单的
把基础知识都说了一遍之后,我们再来推卷积
我们设是不考虑连通性的简单无向图的个数
然后设是考虑连通性后简单无向图的个数,也就是我们需要的答案
然后等式两边同时除以同时把代入
我们发现这个东西满足卷积
然后
然后
求的逆元
然后
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <vector>#include <cmath>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)//#define ivorysiusing namespace std;typedef long long ll;const int MAXN =1<<20;const ll MOD=(479<<21)+1;const int primitive_root=3;int eps_length;int n;struct node {ll x[MAXN];int deg;node(){deg=0;x[0]=0;}};ll inv_fac[MAXN],inv[MAXN];ll w[MAXN],inv_w[MAXN],X[MAXN],choose[MAXN],ans;ll fpow(ll x,ll c) {ll res=1,t=x;while(c) {if(c&1) res=res*t%MOD;t=t*t%MOD;c>>=1;}return res;}void init_w(int L) {ll base=fpow(primitive_root,(MOD-1)/L);ll inv_base=fpow(base,MOD-2);w[0]=1;inv_w[0]=1;xiaosiji(i,1,L) {w[i]=w[i-1]*base%MOD;inv_w[i]=inv_w[i-1]*inv_base%MOD;}eps_length=L;}void FNT(ll *p,int L,ll *eps,int on) {for(int i=1,j=L/2;i<L-1;++i) {if(i<j) swap(p[i],p[j]);int k=L/2;while(j>=k) j-=k,k>>=1;j+=k;}ll u,t;for(int h=2;h<=L;h<<=1) {for(int k=0;k<L;k+=h) {for(int j=k,q=0;j<k+h/2;++j,q+=eps_length/h) {u=p[j];t=eps[q]*p[j+h/2]%MOD;p[j]=(u+t)%MOD;p[j+h/2]=((u-t)%MOD+MOD)%MOD;}}}if(on==-1) {ll inv_L=fpow(L,MOD-2);xiaosiji(i,0,L) {p[i]=p[i]*inv_L%MOD;}}}void calc_Inverse(int n,node &A,node &B) {if(n==1) {B.x[0]=fpow(A.x[0],MOD-2);B.deg=1;return;}calc_Inverse((n+1)>>1,A,B);int L=1;while(L-1 < n*2) L<<=1;xiaosiji(i,0,n) X[i]=A.x[i];xiaosiji(i,n,L) X[i]=0;xiaosiji(i,B.deg,L) B.x[i]=0;FNT(X,L,w,1);FNT(B.x,L,w,1);xiaosiji(i,0,L) {B.x[i]=B.x[i]*(2-X[i]*B.x[i]%MOD+MOD)%MOD;}FNT(B.x,L,inv_w,-1);B.deg=n;}node A,B,C;int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifscanf("%d",&n);int L=1;while(L-1 < (n+1)*2) L<<=1;inv[1]=1;inv_fac[1]=inv_fac[0]=1;siji(i,2,n) {inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;inv_fac[i]=inv[i]*inv_fac[i-1]%MOD;}init_w(L);calc_Inverse(n,A,C);choose[0]=choose[1]=1;siji(i,2,n) {choose[i]=fpow(2,(ll)i*(i-1)/2%(MOD-1));}siji(i,0,n) {A.x[i]=choose[i]*inv_fac[i]%MOD;}siji(i,1,n) {B.x[i]=choose[i]*inv_fac[i-1]%MOD;}calc_Inverse(n+1,A,C);xiaosiji(i,C.deg,L) {C.x[i]=0;}FNT(C.x,L,w,1);FNT(B.x,L,w,1);xiaosiji(i,0,L) {C.x[i]=C.x[i]*B.x[i]%MOD;}FNT(C.x,L,inv_w,-1);ans=C.x[n]*fpow(inv_fac[n-1],MOD-2)%MOD;printf("%lld\n",ans);return 0;}