hdu3658 How many words 矩阵快速幂 + dp

来源:互联网 发布:新垣结衣身高 知乎 编辑:程序博客网 时间:2024/06/05 20:25

http://acm.hdu.edu.cn/showproblem.php?pid=3658

问题:

在52个英文字母里面选择m个字母组成一个字符串。 
满足以下两个条件: 
一、相邻的两个字符的ASCLL码的绝对值小于等于32(比如说X与x的码值差为32); 
二、至少要有一对的字符的绝对值为32。


设置F(32,len)表示  长度为len,相邻字符间隔不超过32的方案数

那么F(32,len)-F(31,len)就是答案(至少有一对等于32)的方案数


那么怎么求F

很显然的一个dp[i][j]表示 长度为i时,最后一个字母为j的方案数

那么递推方程为 dp[i][j]=dp[i-1][k] (abs(j-k)<=limit)

m太大,这样的线性递推可以构造快速幂 

因此只需要维护一个52*52的矩阵即可

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int N = 52;const long long  mod=1000000007;struct Matrix{    long long mat[N][N];} ;Matrix unit_matrix ;long long n ;const int k=52;Matrix mul(Matrix a, Matrix b) //矩阵相乘{    Matrix res;    for(int i = 0; i < k; i++)        for(int j = 0; j < k; j++)        {            res.mat[i][j] = 0;            for(int t = 0; t < k; t++)            {                res.mat[i][j] += a.mat[i][t] * b.mat[t][j];                res.mat[i][j] %= mod;            }        }    return res;}Matrix pow_matrix(Matrix a, long long m)  //矩阵快速幂{    Matrix res = unit_matrix;    while(m != 0)    {        if(m & 1)            res = mul(res, a);        a = mul(a, a);        m >>= 1;    }    return res;}Matrix get(long long n,int limit){    Matrix ori;    memset(  ori.mat ,0,sizeof ori.mat);    for (int i=0;i<52;i++)        ori.mat[0][i]=1;    Matrix c;    memset(  c.mat ,0,sizeof c.mat);    for (int i=0; i<26; i++)    {        for (int j=0; j<26; j++)                c.mat[j][i]=1;        for (int j=26; j<52; j++)        if (  abs(i+32-(j-26))<=limit)        c.mat[j][i]=1;    }    for (int i=26; i<52; i++)    {        for (int j=26; j<52; j++)                c.mat[j][i]=1;          for (int j=0; j<26; j++)        if (  abs(i-32-(j+26))<=limit)        c.mat[j][i]=1;    }    Matrix ans = pow_matrix(c, n-1);    ans = mul(ori,ans);    return ans;}int main(){    int  i, j, t;    //初始化单位矩阵            //类似快速幂的 ans=1; 如今是ans=单位矩阵    memset(unit_matrix.mat,0,sizeof unit_matrix.mat);    for(i = 0; i < k; i++)  unit_matrix.mat[i][i] = 1;    scanf("%d",&t);    while(t--)    {        scanf("%lld",&n);        long long ans1=0,ans2=0;        Matrix tmp=get(n,32);        for (int j=0;j<52;j++)            ans1=(tmp.mat[0][j]+ans1)%mod;        tmp=get(n,31);        for (int j=0;j<52;j++)            ans2=(tmp.mat[0][j]+ans2)%mod;        printf("%lld\n", (ans1-ans2+mod)%mod);    }    return 0;}



0 0
原创粉丝点击