0%

「CTSC2010」性能优化

题目链接

难得写了一次一句话题解/cy

jiqimao:我认为做了 [CTSC2010]性能优化 才算理解 fft。

其实 DFT 的基并不一定为 \(2\),如果保证 \(m\) 次单位根存在(即 \(m\mid (p-1)\) ),我们就可以做基为 \(m\) 的 DFT,如果做一次长度为 \(m\) 的 DFT,其复杂度为 \(O(nm)+mT(\frac{n}{m})\),即我们按照模 \(m\) 的余数分为 \(m\) 个多项式,然后递归下去,再分别带入单位根进行计算就可以了。这道题保证 \(n\) 的每个质因子小于 \(10\),所以复杂度是对的。

也可以按照一般的 FFT 写法写一个蝴蝶变换,我比较懒没写,跑的也不慢。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
using namespace std;
int p,g,gi,a[500005],b[500005],G[500005];
int pw(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=1ll*res*x%p;
x=1ll*x*x%p;
y>>=1;
}
return res;
}
int getroot(int x)
{
for(int i=2;i<=x;i++)
{
bool flag=1;
if(!(x%2))if(pw(i,x/2)==1)flag=0;
if(!(x%3))if(pw(i,x/3)==1)flag=0;
if(!(x%5))if(pw(i,x/5)==1)flag=0;
if(!(x%7))if(pw(i,x/7)==1)flag=0;
if(flag)return i;
}
}
int get(int x)
{
if(!(x%2))return 2;
if(!(x%3))return 3;
if(!(x%5))return 5;
return 7;
}
void dft(int *f,int n,int op)
{
if(n==1)return;
int t=get(n),c=n/t;
int tmp[t][c];
for(int i=0;i<n;i++)tmp[i%t][i/t]=f[i];
for(int i=0;i<t;i++)dft(tmp[i],c,op);
int wn=pw(op==1?g:gi,(p-1)/n);
for(int i=0,ww=1;i<n;i++,ww=1ll*ww*wn%p)
{
f[i]=0;
for(int j=0,w=1;j<t;j++,w=1ll*w*ww%p)
f[i]+=1ll*tmp[j][i%c]*w%p,f[i]%=p;
}
}
int main()
{
int n,c;
scanf("%d%d",&n,&c);
p=n+1;
g=getroot(n);
gi=pw(g,p-2);
for(int i=0;i<n;i++)scanf("%d",&a[i]),a[i]%=p;
for(int i=0;i<n;i++)scanf("%d",&b[i]),b[i]%=p;
dft(a,n,1),dft(b,n,1);
for(int i=0;i<n;i++)a[i]=1ll*a[i]*pw(b[i],c)%p;
dft(a,n,-1);
int t=pw(n,p-2);
for(int i=0;i<n;i++)printf("%lld\n",1ll*a[i]*t%p);
return 0;
}