Codeforces 821E Okabe and El Psy Kongroo 递推+矩阵幂

来源:互联网 发布:mac无法充电 灯不亮了 编辑:程序博客网 时间:2024/05/19 21:42

点击打开链接

题意:n条直线(a[i],b[i],c[i]) 表示在x=a[i]~b[i]内 运动的高度0<=y<=c[i],
a[i]=b[i-1],a[1]=0,a[n]<=k<=b[n],一个人有三个运动方向(x+1,y+1),(x+1,y),(x+1,y-1) 
n<=100,c[i]<=15, a[i],b[i],k<=1e18 问从(0,0)->(k,0)的方法数?


设f[x][y] 从(0,0)到点(x,y)的方法数,
f[x][y]=f[x-1][y]+f[x-1][y-1]+f[x-1][y+1] 注意转移状态时要合法,x>=0&&0<=y<=c[i]

x很大并且x每次都只加1 明显用矩阵幂来优化 s(i,j)为纵坐标i->j的总方法数
构造h^x(i,j) 表示经过x步后 纵坐标从i变化到j的步数

根据每段的c[i],算出h^1,矩阵幂得到h^m,在更新s即可.O(n*h^3*logw)

#include <bits/stdc++.h>using namespace std;typedef long long ll; const int N=20;const int M=2e2;const ll mod=1e9+7;ll s[N][N],h[N][N],t[N][N];//¾­¹ýx²½ºó ×Ý×ø±ê´Ói±äµ½jµÄ·½·¨Êýh[i][j]ll n,K,a[M],b[M],c[M];void mul(ll a[][N],ll b[][N],ll c[][N]){ll t[N][N];for(int i=1;i<=16;i++){for(int j=1;j<=16;j++){t[i][j]=0;for(int k=1;k<=16;k++){t[i][j]+=(a[i][k]*b[k][j])%mod;t[i][j]%=mod;}}}for(int i=1;i<=16;i++)for(int j=1;j<=16;j++)c[i][j]=t[i][j]%mod;}void powmod(ll n){memset(t,0,sizeof(t));for(int i=1;i<=16;i++)t[i][i]=1;while(n){if(n&1)mul(h,t,t);n>>=1;mul(h,h,h);}}int main(){while(cin>>n>>K){memset(s,0,sizeof(s));for(int i=1;i<=n;i++)scanf("%I64d%I64d%I64d",&a[i],&b[i],&c[i]),c[i]++;memset(h,0,sizeof(h));for(int i=1;i<=16;i++)//h^0s[i][i]=h[i][i]=1;for(int x=1;x<=n;x++){memset(h,0,sizeof(h));for(int i=1;i<=c[x];i++){for(int j=1;j<=c[x];j++){if(abs(i-j)<=1)h[i][j]=1;}}ll m=b[x]-a[x];if(x==n)m=K;powmod(m);K-=(b[x]-a[x]);mul(t,s,s);}cout<<s[1][1]<<endl;}return 0;}





阅读全文
0 0
原创粉丝点击