题意:长度为n(1<=n<=10^18)的并且任意连续子串都不是0-k(1<=k<=9)的一个排列的字符串有多少种。
解法:矩阵快速幂。dp[i][j]表示i长度最后连续j个不同(即最后j个无重复,最后j+1个有重复)的字符串的个数。状态选好很重要。设计状态时最重要考虑是唯一性和可传递性,比赛时明明知道肯定是矩阵快速幂,但是一直没想到这个状态表示,自己设计的自己都不会转移。
dp[i][j]有了后,后边加一个字符,这个字符可以是j之内的任意一个,也可以是j以外的,这样枚举每种情况,转移矩阵不难推出。
代码:
/****************************************************** * author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> //freopen ("in.txt" , "r" , stdin); using namespace std; #define eps 1e-8 const double pi=acos(-1.0); typedef long long LL; const int Max=15; const int INF=20140518; int n; LL m; struct Matrix { LL num[Max][Max]; Matrix() { memset(num,0,sizeof num); } }; Matrix operator*(Matrix& a,Matrix& b) { Matrix ans; for(int k=0; k<n; k++) for(int i=0; i<n; i++) for(int j=0; j<n; j++) ans.num[i][j]=(ans.num[i][j]+(a.num[i][k]*b.num[k][j])%INF)%INF; return ans; } Matrix pow(Matrix &a,LL p) { Matrix M; for(int i=0; i<n; i++) M.num[i][i]=1; while(p) { if(p&1) M=M*a; a=a*a; p>>=1; } return M; } int tool[15]; int main() { int t; cin>>t; int kk=1; while(t--) { cin>>m>>n; Matrix M; for(int i=0; i<n; i++) { for(int j=i; j<n; j++) M.num[i][j]=1; } for(int i=1; i<n; i++) M.num[i][i-1]=n-i+1; M=pow(M,m-1); int ans=0; for(int i=0; i<n; i++) ans+=((n+1)*M.num[i][0])%INF,ans%=INF; printf("Case #%d: %d\n",kk++,ans); } return 0; }
2014北京邀请赛E题-矩阵快速幂,布布扣,bubuko.com
原文:http://blog.csdn.net/xiefubao/article/details/26745915