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:到最后求出的是一个前缀和,所以还要做一次差才是答案!!!
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; }
相关文章推荐
- 单片机C语言中define的妙用
- 基于go-ceph创建CEPH块设备及快照
- C++笔试题(十)
- $.ajax()方法解析
- python 装饰器
- Redis Sentinel 机制与用法(二)
- try...catch...finally块嵌入return
- VSphere client建立虚拟机步骤
- 2、HTML基础总结 part-2
- MVC PageList使用(异步 与 正常)
- php分享三十三:常量
- MVC OutPutCache缓存常用属性介绍
- WebStorm 快捷键
- PHP星期几获取代码
- 张小龙首次公开演讲
- 设计模式:备忘录模式
- 获取dropdownlist value text
- 正则表达式测试
- 使用Coverage分析Python web项目的代码覆盖率
- 值得推荐的C/C++框架和库