BZOJ 2323: [ZJOI2011]细胞

来源:互联网 发布:健身数据统计 编辑:程序博客网 时间:2024/05/17 02:29

好题啊!! 矩乘+DP
蒟蒻的我一开始发现了斐波那契数列之后就不会搞了。。
那个。。什么质量相同两种方案相同就是扯淡的。。想想就知道没有这种情况

先来说一下为什么是斐波那契
假设最后有n个点 则有n-1条东西 如果用f[x][0/1] 表示第x条割还是不割
不难得到方程f[x][0]=f[x-1][1],f[x][1]=f[x-1][0]+f[x-1][1] 答案是f[n-1][1] (最后一条一定要割)
化一下就是f[x][1]=f[x-1][1]+f[x-2][1] 嗯。。其实是不是斐波那契都行 因为变成矩乘都一样(不要问我为什么)

答案就是所有分割方案的

Fib[s2]

可是你知道s会很大。。大到快速幂也玩不了
这时还需要一个按位的dp
f[i]=1<=j<=if[j1]knum[j,i]

num[j,i]表示j到i表示的数
K就是斐波那契矩阵
0111

因此我们来进行拆位 预处理出k的10进制次幂(^10,^100,^1000…)
为了方便 让 f数组用矩阵表示
f[0]=k2

答案就是
f[n]2,2

代码还是挺好看的

#include<bits/stdc++.h>#define me(a,x) memset(a,x,sizeof a)using namespace std;typedef long long LL;const int N=1005;const LL mod=1000000007;inline int read(){    char ch=getchar(); int x=0,f=1;    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}    return x*f;}struct P{    LL c[3][3];    P(){me(c,0);}}a[N],f[N];char s[N]; int n;P cheng(P a,P b){    P c;    for(int i=1;i<3;i++)for(int j=1;j<3;j++)        for(int k=1;k<3;k++)(c.c[i][j]+=(a.c[i][k]*b.c[k][j])%mod)%=mod;    return c;}void add(P &a,P b){    for(int i=1;i<3;i++)for(int j=1;j<3;j++)(a.c[i][j]+=b.c[i][j])%=mod;}int main(){    scanf("%d%s",&n,s+1);    f[0].c[1][1]=2,f[0].c[1][2]=f[0].c[2][1]=-1,f[0].c[2][2]=1;    a[0].c[1][2]=a[0].c[2][1]=a[0].c[2][2]=1;    int i,j;    for(i=1;i<=n;i++)    {        P u=a[i]=a[i-1];        for(int x=9;x;x>>=1,u=cheng(u,u))            if(x&1)a[i]=cheng(a[i],u);    }    for(i=1;i<=n;i++)    {        P k; k.c[1][1]=k.c[2][2]=1;        for(j=i;j>0;j--)        {            int x=s[j]-'0';            while(x--)k=cheng(k,a[i-j]);            add(f[i],cheng(f[j-1],k));        }    }    printf("%lld\n",(f[n].c[2][2]+mod)%mod);    return 0;}
1 0
原创粉丝点击