BZOJ 2323: [ZJOI2011]细胞
嗯。。csdn发得出markdown了。。请移步~ 个人觉得那个帅一点 嗯
好题啊!! 矩乘+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[s-2]
可是你知道s会很大。。打到快速幂也玩不了
这时还需要一个按位的dp
f[i] = ∑ f[j-1]*k^x (1<=j<=i)
x表示j到i表示的数
K就是斐波那契矩阵
0 1
1 1
因此我们来进行拆位 预处理出k的10进制次幂(10,100,^1000...)
为了方便 让 f数组用矩阵表示 f[0]=k^(-2)
答案就是 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;
}