[ZJOI2011]細胞——斐波那契數列+矩陣加速+dp

來源:互聯網
上載者:User

標籤:har   矩陣加速   現在   一個   [1]   operator   a*   bsp   方式   

Description

bzoj2323

Solution

題目看起來非常複雜。

本質不同的細胞這個條件顯然太囉嗦,

是否有些可以挖掘的性質?

 

1.發現,只要第一次分裂不同,那麼互相之間一定是不同的(即使總數目相同)。

所以先考慮第一次分裂後,一個固定小球體數量的情況:

2.第一次分裂後,最後的小球體數量固定。想要方案數不同,必須串連方式不同。

可以列出dp式子,f[n](以n結尾砍一刀)=f[n-2]+f[n-3]+...+f[2]+f[0],而f[0]=1,f[1]=0

而fibo[n]-1=f[n-2]+...+f[1]

可以猜想和斐波那契數列有關。

實際上,f[n]=fibo[n-1],f[1]=0,f[0]=1

所以,如果我們知道第一次分裂的方案,

即S=a1+...+am(分成m段,ai表示這一段拼成的數字)

那麼,f[S]=fibo[S-1]

 

好了,

所以,題意其實是:


? 給出一個數字序列
? 你要先把序列切成很多段,把每一段看做一個十進位數
??1, ??2, … , ????
? 你要求每一種分割方案的 Fib (??1 + ? + ???? )的和
? ?? ≤ 1000

現在我們的問題就是怎樣快速統計這些所有fibo的和。

設f[i]表示,前i個,i後劈一刀,所有產生的Fib (??1 + ? + ??k )的和。

 

由於矩陣有結合律和分配律,

Fibo[i]=Start*(M^j*M^(i-j))(M是轉移矩陣)

我可以把f用矩陣表示

經典n^2的dp

然後,我們要快速統計M^(num[j...i])

直接每次高精精快速冪??(逗笑)

 

根據套路,可以利用j每次向左走一位,在路上利用之前的基礎統計出num[j...i]

那麼,我麼就要知道所有的K=a*10^p,M^K可以預先處理。

然後直接M^num=M^(K+old)=M^k*M^old

即可統計出num[j...i]

 

轉移的時候,f[i]+=f[j]*M^(num[j+1...i])即可,因為乘法分配律,dp式子成立。

注意下,f[S]=Fibo[S-1]

所以,其實f[0]=[0,1,0,0](寫成矩陣)

總之,如果j==0,那麼這個段是第一段,直接把這個1減掉。相當於對矩陣乘一個逆

 

代碼:

(注意,逆矩陣:[mod-1,1,1,0]而不是[-1,1,1,0]。不要爆負數)

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int N=1005;const int mod=1e9+7;int n;char s[N];struct tr{    ll a[3][3];    void pre(){        memset(a,0,sizeof a);    }    void init(){        a[1][1]=a[2][2]=1;    }    tr operator *(const tr &b){        tr c;c.pre();        for(int i=1;i<=2;i++)         for(int k=1;k<=2;k++)          for(int j=1;j<=2;j++)           c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%mod;        return c;    }    tr operator +(const tr &b){        tr c;c.pre();        for(int i=1;i<=2;i++)         for(int j=1;j<=2;j++)          c.a[i][j]=(a[i][j]+b.a[i][j])%mod;        return c;    }    void op(){        cout<<endl;        for(int i=1;i<=2;i++){            for(int j=1;j<=2;j++){                cout<<a[i][j]<<" ";            }cout<<endl;        }        cout<<endl;    }}B[10][1005],f[1005],A,C,D;tr qm(tr c,ll y){    tr ret;ret.pre();ret.init();    while(y){        if(y&1) ret=ret*c;        c=c*c;        y>>=1;    }    return ret;}void prewrk(){    for(int i=0;i<=9;i++) B[i][0]=qm(A,i);    for(int i=1;i<=n;i++){        for(int j=0;j<=9;j++){            B[j][i]=qm(B[j][i-1],10);        }    }}int main(){    scanf("%d",&n);    A.a[1][1]=0;A.a[1][2]=1;A.a[2][2]=1;A.a[2][1]=1;    D.a[1][1]=mod-1;D.a[1][2]=1;D.a[2][1]=1;D.a[2][2]=0;    prewrk();    scanf("%s",s+1);    //cout<<" hh "<<endl;    f[0].a[1][2]=1;    for(int i=1;i<=n;i++){        C.pre();C.init();        //cout<<i<<"------------"<<endl;        for(int j=i-1;j>=0;j--){            //cout<<s[j+1]-‘0‘<<endl;            C=C*B[s[j+1]-‘0‘][i-j-1];            //C.op();            //cout<<">>"<<endl;            if(j==0) C=C*D;            tr tmp=f[j]*C;            f[i]=f[i]+tmp;            //cout<<" f[i] "<<endl;            //f[i].op();        }    }    printf("%lld\n",f[n].a[1][1]);    return 0;}

 

[ZJOI2011]細胞——斐波那契數列+矩陣加速+dp

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.