HDU - 5863 - cjj's string game (递推)

题目连接: HDU - 5863 - cjj’s string game

S 为到当前长度时,所有出现过长度为 m 的子串,之后字母都相异的情况数量之和。

dp1[i] 为相同后缀长度为 i 且之前从未出现过长度为 m 的子串情况数量。

dp2[i] 为相同后缀长度为 i 且之前出现过长度为 m 的字符串的数量。

进行计数转移就行。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=30;
ll n;
int m,k;
struct Matrix
{
    ll a[N][N];
    int n;
    Matrix(int n) : n(n) { memset(a,0,sizeof(a)); }
    ll * operator [] (int index) { return a[index]; }
    Matrix operator * (Matrix& b)
    {
        Matrix c(n);
        for(int i=0;i<n;++i)
            for(int k=0;k<n;++k)
                for(int j=0;j<n;++j)
                    c[i][j]=(c[i][j]+a[i][k]*b[k][j]%mod)%mod;
        return c;
    }
};
Matrix powm(Matrix a, ll b)
{
    int n=a.n;
    Matrix c(n);
    for(int i=0;i<n;++i)
        for(int j=0;j<n;++j)
            c[i][j]=(i==j);
    while(b)
    {
        if(b&1) c=c*a;
        a=a*a;
        b>>=1;
    }
    return c;
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m >> k;
        Matrix M((m+1)*2+1);
        for(int i=0;i<m;++i)
            M[0][i]=k*(k-1);
        for(int i=1;i<=m;++i)
            M[i][i-1]=k;
        for(int i=m+1;i<=2*m+1;++i)
            M[m+1][i]=k*(k-1);
        for(int i=m+2;i<=m*2+1;++i)
            M[i][i-1]=k;
        M[m+1][2*m+1]=k*(k-1);
        M[m+1][m]=k*(k-1);
        for(int i=m+1;i<=m*2;++i)
            M[i+1][i]=k;
        M[2*m+2][2*m+2]=k*(k-1);
        M[2*m+2][m-1]=k;
        for(int i=m+1;i<=2*m;++i) M[2*m+2][i]=k;
        M=powm(M,n);
        cout << M[2*m+2][0] << endl;
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值