首页 > 其他 > 详细

Codeforces 1426F - Number of Subsequences (dp)

时间:2020-10-01 23:49:30      阅读:43      评论:0      收藏:0      [点我收藏+]

Codeforces Round #674 (Div. 3) F - Number of Subsequences


题意

给定一个长度为\(n\)字符串,仅包含\(\{a,b,c,?\}\)这四种字符。

字符\(?\)为通配符,可以匹配\(\{a,b,c\}\)三种字符中的任意一种。如果字符串内含有\(k\)个通配符,则最终可以得到\(3^k\)个不同字符串。

问在这\(3^k\)个不同字符串内有多少为"abc"的子序列,答案对\(10^9+7\)取模。


限制

\(3\leq n\leq 200000\)




思路

考虑同时对\(3^k\)个字符串进行dp

建立三种dp状态,分别表示处理到当前位置时子序列为"a","ab","abc"的个数

新建一个变量\(cnt\),储存处理到某个位置时出现了多少个不同的字符串,初始时可以当作只有一种字符串


按顺序遍历给定的字符串:


如果当前字符为‘a‘,则表示子序列为"a"的个数需要新增\(cnt\)个。(\(dp[a]=dp[a]+cnt\)

如果当前字符为‘b‘,则表示子序列"ab"可以由当前的‘b‘以及之前出现的‘a‘拼接出来,个数可以新增\(dp[a]\)个。(\(dp[ab]=dp[ab]+dp[a]\)

如果当前字符为‘c‘,同样表示子序列"abc"可以由当前的‘c‘以及之前出现的"ab"拼接出来,个数可以新增\(dp[ab]\)个。(\(dp[abc]=dp[abc]+dp[ab]\)


如果当前字符为‘?‘,可以通配为三种字符的任意一种,此时不同的字符串数量会变成原本的\(3\)倍。

这就表示,如果暂时不考虑这个‘?‘带来的影响,那么之前计数中出现的\(dp[a]\ /\ dp[ab]\ /\ dp[abc]\)都要变成原先的\(3\)倍。

再考虑‘?‘带来的影响,分别考虑它是三种字符的任意一种带来的影响,可以得到与上方三类讨论相同。(按顺序执行下述过程)

\[\begin{aligned} dp[a]&=dp[a]*3\dp[ab]&=dp[ab]*3\dp[abc]&=dp[abc]*3\dp[abc]&=dp[abc]+dp[ab]\dp[ab]&=dp[ab]+dp[a]\dp[a]&=dp[a]+cnt\cnt&=cnt*3 \end{aligned} \]

最后\(dp[abc]\)即代表答案。




程序

(46ms/1000ms)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;

char s[200050];
int main()
{
    int n;
    scanf("%d%s",&n,s+1);
    ll dp[3]={0,0,0},cnt=1;
    for(int i=1;i<=n;i++)
    {
        if(s[i]==‘a‘)
            dp[0]=(dp[0]+cnt)%mod;
        else if(s[i]==‘b‘)
            dp[1]=(dp[1]+dp[0])%mod;
        else if(s[i]==‘c‘)
            dp[2]=(dp[2]+dp[1])%mod;
        else
        {
            dp[2]=(dp[2]*3+dp[1])%mod;
            dp[1]=(dp[1]*3+dp[0])%mod;
            dp[0]=(dp[0]*3+cnt)%mod;
            cnt=cnt*3%mod;
        }
    }
    printf("%lld\n",dp[2]);
    
    return 0;
}

Codeforces 1426F - Number of Subsequences (dp)

原文:https://www.cnblogs.com/stelayuri/p/13758798.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!