2014北京邀请赛E题_BNU_44673_Elegant String(DP+矩阵快速幂)

来源:互联网 发布:如何提高淘宝产品权重 编辑:程序博客网 时间:2024/06/09 21:38

题型:动态规划+矩阵快速幂


题意:N长度的串中的任意子串都不是0~K的全排列的构造方法数。


分析:

       设dp[i][j]表示i长度最后连续j个字符无重复(j+1有重复)的字符串的个数。对于下一个状态,无非是两种情况,一种是j之内的任意一个,一种是j个字符以外的一个,这样可以推导出状态转移方程:




       由于N范围是10^18,所以不能递推跑出,但是有了递推式,就可以采用矩阵快速幂

       观察状态转移方程:

        dp[i][1] = dp[i-1][1] + k * dp[i-1][2]

        dp[i][2] = dp[i-1][1] + dp[i-1][2] + (k-1) * dp[i-1][3]

         ……

        dp[i][k-1] = dp[i-1][1] + dp[i-1][2] + …… + dp[i-1][k-1] + 2 * dp[i-1][k]

        dp[i][k] = dp[i-1][1] + dp[i-1][2] + …… + dp[i-1][k]

        这样一看,就可以轻松推出变换矩阵了

        

====>




===>       

              ans = dp[N][1]



代码:

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#define mt(a,b) memset(a,b,sizeof(a))#define LL long longusing namespace std;const LL M = 50LL;const LL mod = 20140518LL;class Matrix {    typedef long long typev;public:    typev val[M][M];    void zero() {        memset(val,0,sizeof(val));    }    void unit() {        zero();        for(LL i=0; i<M; i++) val[i][i]=1;    }} ts,tmp;LL LEN;Matrix operator * (const Matrix &a,const Matrix &b) {    Matrix tmp;    tmp.zero();    for(LL k=0; k<LEN; k++)        for(LL i=0; i<LEN; i++) {            if(a.val[i][k])                for(LL j=0; j<LEN; j++) {                    tmp.val[i][j]+=a.val[i][k]*b.val[k][j];                    tmp.val[i][j]%=mod;                }        }    return tmp;}Matrix operator ^ (Matrix &a,LL p) {    Matrix tmp;    tmp.unit();    while(p) {        if(p&1) tmp=tmp*a;        a=a*a;        p>>=1;    }    return tmp;}void init(LL k) {    for(LL i=0; i<LEN; i++) {        for(LL j=0; j<LEN; j++) {            if(i>=j) {                ts.val[i][j] = 1;            } else if(i+1 == j) {                ts.val[i][j] = k;                k--;            } else continue;        }    }}void OUTPUT() {    for(LL i=0; i<LEN; i++) {        for(LL j=0; j<LEN; j++) {            printf("%d ",ts.val[i][j]);        }        puts("");    }}void OUTPUT1() {    for(LL i=0; i<LEN; i++) {        for(LL j=0; j<LEN; j++) {            printf("%d ",tmp.val[i][j]);        }        puts("");    }}LL DP1[50],DPn[50];void LastSolve(LL k) {    mt(DPn,0);    for(LL i=0; i<k; i++) {        LL sum = 0;        for(LL j=0; j<k; j++) {            sum += (tmp.val[i][j] * DP1[j])%mod;        }        DPn[i] = sum % mod;    }}int main() {    int cas,_;    LL n,k;    scanf("%d",&cas);    for(_=1; _<=cas; _++) {        scanf("%lld%lld",&n,&k);        LEN = k;        ts.zero();        init(k);        //OUTPUT();        for(LL i=0; i<k; i++) {            DP1[i] = k+1;        }        tmp.zero();        tmp = ts^(n-1);        //OUTPUT1();        LastSolve(k);        printf("Case #%d: ",_);        printf("%lld\n",DPn[0]%mod);    }    return 0;}


        

0 0
原创粉丝点击