CQOI2018 九连环 打表找规律 fft快速傅里叶变换

题面:

  CQOI2018九连环

分析:

  个人认为这道题没有什么价值,纯粹是为了考算法而考算法。

  对于小数据我们可以直接爆搜打表,打表出来我们可以观察规律。

  f[1~10]: 1 2 5 10 21 42 85 170 341 682

  我们可以发现的规律是,当i为奇数时,f[i]=f[i-1]*2+1,偶数时f[i]=f[i-1]*2。

  既然这样,我们可以推断通项公式是否跟2的次幂有关。

  我们连蒙带猜连导带推,可以得出,f[i]=2^(i+1)/3(下取整)。

  再结合数据范围,我们可以决定是写fft+快速幂还是写python

  这样这道题就结束了。

代码:

 1 #include<bits/stdc++.h>
 2 #define db double
 3 #define ll long long
 4 #define cp complex<db>
 5 using namespace std;
 6 const int N=70000;
 7 const db pi=acos(-1);int r[N];
 8 void fft(cp *a,int *r,int lm,int op){
 9     for(int i=0;i<lm;i++) 
10     if(i<r[i]) swap(a[i],a[r[i]]);
11     for(int mid=1;mid<lm;mid<<=1){
12         cp wn;wn=cp(cos(pi/mid),op*sin(pi/mid));
13         for(int R=mid<<1,j =0;j<lm;j+=R){
14             cp w;w=cp(1,0);
15             for(int k=0;k<mid;k++,w=w*wn){
16                 cp x=a[j+k],y=w*a[j+mid+k];
17                 a[j+k]=x+y;a[j+mid+k]=x-y;
18             }
19         }
20     } return ;
21 } struct big{
22     int g[N],len;
23     big(){
24         memset(g,0,sizeof(g));len=1;
25     } big(int x){
26         memset(g,0,sizeof(g));len=0;
27         if(!x){len=1;return ;}
28         while(x) g[len++]=x%10,x/=10;
29     } void operator *=(const big &b){
30         static cp A[N],B[N];
31         int nl=len+b.len,lm=1,L=0;
32         while(lm<nl) lm<<=1,++L;
33         for(int i=0;i<lm;i++)
34         A[i]=cp(i<len?g[i]:0,0),
35         B[i]=cp(i<b.len?b.g[i]:0,0);r[0]=0;
36         for(int i=0;i<lm;i++)
37         r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
38         fft(A,r,lm,1);fft(B,r,lm,1);
39         for(int i=0;i<lm;i++) A[i]*=B[i];
40         fft(A,r,lm,-1);int ans[N];
41         for(int i=0;i<lm;i++)
42         ans[i]=(int)(A[i].real()/lm+0.5);
43         for(int i=0;i<lm;i++)
44         if(ans[i]>9) ans[i+1]+=ans[i]/10,
45         ans[i]%=10;lm--;
46         while(lm>0&&!ans[lm]) lm--;len=++lm;
47         for(int i=0;i<lm;i++) g[i]=ans[i];
48     } void operator /= (int x){
49         int sm=0,nl=0;
50         for(int i=len-1;~i;i--){
51             sm=sm*10+g[i];
52             if(sm<x) g[i]=0;
53             else{
54                 if(!nl) nl=i+1;
55                 g[i]=sm/x,sm%=x;
56             }
57         } len=max(nl,1);
58     } void print(){
59         for(int i=len-1;~i;i--)
60         printf("%d",g[i]);puts("");
61     }
62 }ret,bs;
63 int main(){
64     int t;scanf("%d",&t);while(t--){
65         int n;scanf("%d",&n);n++;
66         ret=big(1);bs=big(2);
67         while(n){
68             if(n&1) ret*=bs;
69             bs*=bs;n>>=1;
70         } ret/=3;ret.print();
71     } return 0;
72 }
fft快速傅里叶变换

 

posted @ 2019-02-21 17:39  杜宇一声  阅读(210)  评论(0编辑  收藏  举报