禁止字符串(挑战程序设计368页)

时间:2019-10-14
本文章向大家介绍禁止字符串(挑战程序设计368页),主要包括禁止字符串(挑战程序设计368页)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意:考虑只由'A','G','C','T'四种字符组成的DNA字符串。给定一个长度为k的字符串S。计算长度恰好为n且不包含S的字符串的个数。输出答案mod 10009的结果

题解:

对于每一个串s,都可能由一些状态转移到另外一些状态。例如: S=“ATCATCG”,假设我当前s=AATC,而这个状态所对应的状态为*ATC,假如我在这个AATC后加上A,那么s就会转移到*A这个状态。

为什么呢,因为我如果要组成S的话,那么前缀必定相等,所以就会有这样的转移关系!所以就可以用动态规划求解

技巧:先预处理出添加某个字符后转移到的状态表,之后根据一些简单的判断就可以进行DP了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define pb push_back
const int mod=10009;
void read(int &a)
{
    a=0;int d=1;char ch;
    while(ch=getchar(),ch>'9'||ch<'0')
        if(ch=='-')
            d=-1;
    a=ch^48;
    while(ch=getchar(),ch>='0'&&ch<='9')
        a=(a<<3)+(a<<1)+(ch^48);
    a*=d;
}
int n,k;
string S;
int next[10009][5];///添加某个字符后转移到的状态
int dp[10009][105];
char AGCT[5]={'A','G','C','T'};
void solve()
{
    for(re int i=0;i<k;i++)
    {
        for(re int j=0;j<4;j++)
        {
            string s=S.substr(0,i)+AGCT[j];///截取S的前i个字符,然后加题目给定的4个字符之一
            while(S.substr(0,s.length())!=s)///当S的前缀不是s时做循环
                s=s.substr(1);///取s以1之后的所有字符,相当于删除第一个字符后剩下的所有字符
            next[i][j]=s.length();///添加j字符后转移到的状态的字符前缀长度
        }
    }
}
int main()
{
    read(n),read(k);cin>>S;
    solve();
    dp[0][0]=1;
    for(re int i=1;i<k;i++) dp[0][i]=0;
    for(re int t=0;t<n;t++)
    {
        for(re int i=0;i<k;i++) dp[t+1][i]=0;
        for(re int i=0;i<k;i++)
        {
            for(re int j=0;j<4;j++)
            {
                int ti=next[i][j];
                if(ti==k) continue;///如果当前字符前缀长度已经为k,那么明显是不符合要求的
                //cout<<ti<<" "<<i<<endl;
                dp[t+1][ti]=(dp[t+1][ti]+dp[t][i])%mod;///t+1长度的,只要当前next[i][j]匹配长度不为k,那么ti可以由i转移过来,所以就有这个转移式!!!
            }
        }
    }
    int ans=0;
    for(re int i=0;i<k;i++) ans=(ans+dp[n][i])%mod;///将长度为n的,与S匹配最长为i的串全部累加就是答案
    printf("%d\n",ans);
}

原文地址:https://www.cnblogs.com/acm1ruoji/p/11671879.html