CF_137_div2_E_Decoding Genome 题解

该博客解析了一道编程题目,题目要求在给定限制条件下计算符合条件的字符串数量。博主首先介绍了不考虑时间复杂度的直接解法,然后由于题目规模导致的超时问题,提出了利用矩阵快速幂优化算法来解决。博主详细解释了矩阵快速幂的思路,并给出了源代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Brief Description:

一个字符串由n个字符组成,字符只能是大小写的字母(a->z,A->Z),其中a对应0,b对应1.....z对应25,A对应26,B对应27,Z对应51,且字符只能取编号0->m,现在规定某2个字符不能靠在一起,求这样的字符串有多少个。

Analysis:

先不考虑题目的规模,我们定义sum[i][j]:取前i个字符,第i个字符时j,能组成多少个字符串

则有sum[i][j] = sigma(sum[i-1][k]) 且k,j可以靠在一起,时间复杂度为O(26*n).

由于n <= 1e+15,这么做会超时 ,所以只能另辟蹊径!

怎么做呢?线性操作可以考虑矩阵快速幂~正解就是矩阵快速幂。

我们知道sum[1][j] = 1。 0<=j<m

定义矩阵M = (num[i][j]),若i,j可以靠在一起,num[i][j]=1,否则num[i][j]=0

我们用矩阵ansM=(sum[1][0],sum[1][1]....sum[1][m-1])*M^n-1,ansM的第i列数总和就是sum[n][i],

最后我们只需将ansM中的所有数加起来便是答案。

源代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define M 1000000007
using namespace std;
typedef long long LL;
struct Matrix
{
    LL num[64][64];
};
LL n;
int m,K;
LL G[64][64];
Matrix mul(Matrix p,Matrix q) {
     Matrix ret;
     for(int i=0; i<m; i++) for(int j=0; j<m; j++) {
        ret.num[i][j] = 0;
        for(int k=0; k<m; k++) {
           ret.num[i][j] += p.num[i][k] * q.num[k][j];
           ret.num[i][j] %= M;
        }
     }
     return ret;
}
Matrix f()
{
    Matrix ret,p;
    memset(ret.num,0,sizeof(ret.num));
    for(int i=0; i<m; i++) ret.num[i][i] = 1;
    for(int i=0; i<m; i++) for(int j=0; j<m; j++) p.num[i][j] = G[i][j];

    n--;
    while(n)
    {
        if(n & 1)
          ret = mul(ret,p);
        p = mul(p,p);
        n >>= 1;
    }
    return ret;
}

int main()
{
    while(scanf("%I64d%d%d",&n,&m,&K) == 3)
    {
        int i,j;
        for(i=0; i<m; i++) for(j=0; j<m; j++) G[i][j] = 1;
        while(K--)
        {
            char c1,c2;
            int x,y;
            scanf(" %c %c",&c1,&c2);
            x = c1>='a'&&c1<='z'?c1-'a':c1-'A'+26;
            y = c2>='a'&&c2<='z'?c2-'a':c2-'A'+26;
            G[x][y] = 0;
        }
        Matrix ansM = f();
      //  for(i=0; i<m; i++)
        LL ans = 0;
        for(i=0; i<m; i++)
        {
            for(j=0; j<m; j++)
            {
                ans += ansM.num[i][j];
                ans %= M;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值