BZOJ 5300: [Cqoi2018]九连环 打表+FFT

仔细观察样例解释,发现 $F(n)=2F(n-1)+[n \%2]$.       

然后我们就可以推出来前 10 项左右的 $F(n)$ 的值,然后打表找规律发现 $F(n)=\frac{2^{n+1}}{3}$ (向下取整) 

由于没有模数,所以需要手写一个 $FFT$ 维护高精度乘法的板子. 

code: 

#include <cstdio> 
#include <cmath> 
#include <cstring> 
#include <algorithm> 
#define setIO(s) freopen(s".in","r",stdin)  
using namespace std;   
const int N=4000006;   
const double pi=acos(-1);     
char S[N];  
struct cp
{   
    double x,y;   
    cp(double a=0,double b=0) { x=a,y=b; }    
    cp operator+(const cp b) { return cp(x+b.x,y+b.y); }  
    cp operator-(const cp b) { return cp(x-b.x,y-b.y); }  
    cp operator*(const cp b) { return cp(x*b.x-y*b.y,x*b.y+y*b.x); } 
}A[N],B[N]; 
int mem[N*10],*ptr=mem;            
void FFT(cp *a,int len,int flag) 
{
    int i,j,k,mid;  
    for(i=k=0;i<len;++i) 
    {
        if(i>k) swap(a[i],a[k]);   
        for(j=len>>1;(k^=j)<j;j>>=1);  
    }
    for(mid=1;mid<len;mid<<=1) 
    {
        cp wn(cos(pi/mid), flag*sin(pi/mid)),x,y;
        for(i=0;i<len;i+=mid<<1)
        {
            cp w(1,0);
            for(j=0;j<mid;++j)
            {
                x=a[i+j],y=w*a[i+j+mid];  
                a[i+j]=x+y,a[i+j+mid]=x-y; 
                w=w*wn;        
            }
        }  
    }
    if(flag==-1) 
    {
        for(i=0;i<len;++i) a[i].x/=(double)len;     
    }
}
struct num
{        
    int len; 
    int *a;
    num(){}  
    num(int l) { len=l,a=ptr,ptr+=l; }       
    void fix(int l) { len=l,a=ptr,ptr+=l; }          
    void get_mod(int l) { len=l; }
    num operator*(const num &b) 
    {       
        num c(len+b.len+1);             
        int lim=1,i,j,l=b.len;   
        while(lim<=c.len) lim<<=1;                        
        for(i=0;i<lim;++i) 
        {
            A[i].x=A[i].y=0; 
            B[i].x=B[i].y=0;   
        } 
        for(i=0;i<len;++i) A[i].x=a[i];    
        for(i=0;i<b.len;++i) B[i].x=b.a[i];          
        FFT(A,lim,1),FFT(B,lim,1);   
        for(i=0;i<lim;++i) A[i]=A[i]*B[i];   
        FFT(A,lim,-1);   
        for(i=0;i<c.len;++i) c.a[i]=(int)(A[i].x+0.5);    

        for(i=0;i<c.len-1;++i) 
        {   
            c.a[i+1]+=c.a[i]/10;                 
            c.a[i]%=10;      
        }
        for(i=c.len-1;i>=0;--i)  if(c.a[i]) break;              
        c.get_mod(i+1);     
        return c;   
    }          
    num operator/(const int b)     
    {
        num c(len);       
        int i,j,re=0;     
        for(i=len-1;i>=0;--i) 
        {
            re=re*10+a[i];          
            c.a[i]=re/b;                  
            re%=b;          
        }     
        for(i=c.len-1;i>=0;--i) 
        { 
            if(c.a[i]) break;  
        }
        c.get_mod(i+1);   
        return c;     
    } 
    void print() { for(int i=len-1;i>=0;--i) printf("%d",a[i]); }        
    void input() 
    { 
        scanf("%s",S);     
        int l=strlen(S);    
        fix(l);                      
        for(int i=0;i<l;++i) a[i]=S[l-1-i]-'0';     
    }   
}t,tmp;         
void qpow(int y) 
{
    while(y) 
    { 
        if(y&1) tmp=tmp*t;      
        y>>=1;  
        t=t*t;    
    }   
}      
int main() 
{   
    // setIO("input");    
    int m;   
    scanf("%d",&m);     
    while(m--) 
    {
        int n;   
        scanf("%d",&n);   
        tmp.fix(1),t.fix(1);    
        tmp.a[0]=1,t.a[0]=2;          
        qpow(n+1);         
        tmp=tmp/3;   
        tmp.print();     
        printf("\n");         
    }
    return 0;      
} 

  

posted @ 2020-02-02 16:44  EM-LGH  阅读(123)  评论(0编辑  收藏  举报