题意:长度为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