您的位置:首页 > 其它

4417: [Shoi2013]超级跳马|DP+矩阵快速幂

2016-03-15 10:37 309 查看
DP比较显然,用到矩阵乘法快速幂需要一点转换。

F1[i][j]F_{1}[i][j]表示从起点走到第(2∗i−1)(2*i-1)列,第jj行的方案数

F2[i][j]F_{2}[i][j]表示从起点走到第(2∗i)(2*i)列,第jj行的方案数

转移就是:

F1[i][j]=∑k<iF2[k][j−1]+F2[k][j]+F2[k][j+1]F_{1}[i][j]=\sum_{k

F2[i][j]=∑k<=iF1[k][j−1]+F1[k][j]+F1[k][j+1]F_{2}[i][j]=\sum_{k<=i}F_{1}[k][j-1]+F_{1}[k][j]+F_{1}[k][j+1]

显然需要分别把F1F_{1}和F2F_{2}数组转化为前缀和的形式,这样转移的复杂度就是O(1)O(1)

转化为前缀和之后的转移:

F1[i][j]=F1[i−1][j]+F2[i−1][j−1]+F2[i−1][j]+F2[i−1][j+1]F_{1}[i][j]=F_{1}[i-1][j]+F_{2}[i-1][j-1]+F_{2}[i-1][j]+F_{2}[i-1][j+1]

F2[i][j]=F2[i−1][j]+F1[i][j−1]+F1[i][j]+F1[i][j+1]F_{2}[i][j]=F_{2}[i-1][j]+F_{1}[i][j-1]+F_{1}[i][j]+F_{1}[i][j+1]

这样每一次转移都是相同的,然后就可以用矩阵快速幂加速转移。

PS:PS:到最后求出的是一个前缀和,所以还要做一次差才是答案!!!

#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define p 30011
using namespace std;
struct matrix {int a[110][110];}a,b,c;
int a1[110][110],a2[110][110],f[110];
int n,m,L;
matrix operator *(matrix a,matrix b)
{
matrix c;
for(int i=1;i<=L;i++)
for(int j=1;j<=L;j++)
{
c.a[i][j]=0;
for(int k=1;k<=L;k++)
(c.a[i][j]+=a.a[i][k]*b.a[k][j])%=p;
}
return c;
}
int main()
{
scanf("%d%d",&n,&m);L=2*n;
if(m==2)
{
printf("%d\n",n>2?0:1);
return 0;
}
for(int i=1;i<=n;i++)
{
a2[i][i]=a2[i+n][i+n]=a1[i][i]=a1[i+n][i+n]=1;
a1[i+n][i]=a2[i][i+n]=1;
if(i>1)a1[i+n-1][i]=a2[i-1][i+n]=1;
if(i<n)a1[i+n+1][i]=a2[i+1][i+n]=1;
}
for(int i=1;i<=L;i++)
for(int j=1;j<=L;j++)
for(int k=1;k<=L;k++)
(a.a[i][j]+=a1[i][k]*a2[k][j])%=p;
c=a;
for(int i=1;i<=L;i++)b.a[i][i]=1;
for(int y=(m-1)/2-1;y;y>>=1,a=a*a)if(y&1)b=b*a;
c=b*c;
int x=2*n;if(m&1)x-=n;
int ans=(c.a[1][x]+c.a[n+1][x]+c.a[n+2][x]-(ans=b.a[1][x]+b.a[n+1][x]+b.a[n+2][x]))%p;
printf("%d\n",(ans+p)%p);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: