题意

给定一个长度为 \(n\) 的串,只包含 abc 和通配符。通配符可以替换 abc 的一个。求所有得到的字符串中子序列 abc 出现的次数,对 \(10^9+7\) 取模。

\(\texttt{Data Range:}n\leq 2\times 10^5\)

题解

哇哈哈哈我智商终于恢复了。

比较套路,但其实这个东西我一开始是用类似于期望的东西来想的。

记通配符的数量为 \(m\)。

考虑设 \(f_{i,j}\) 表示所有 \(3^m\) 个字符串的前 \(i\) 个字符中,子序列 aababc 的数量之和。

首先当给定字符串的第 \(i\) 个字符为 a 的时候,有如下转移:

\[f_{i,1}=f_{i-1,1}+3^m,f_{i,2}=f_{i-1,2},f_{i,3}=f_{i-1,3}
\]

b 的时候有如下转移:

\[f_{i,1}=f_{i-1,1},f_{i,2}=f_{i-1,2}+f_{i-1,1},f_{i,3}=f_{i-1,3}
\]

c 的时候有如下转移:

\[f_{i,1}=f_{i-1,1},f_{i,2}=f_{i-1,2},f_{i,3}=f_{i-1,3}+f_{i-1,2}
\]

这三个转移都很平凡,这里不多赘述。

接下来是为通配符的情况,需要讨论一下。

注意到我们肯定可以将所有 \(3^{m}\) 个字符串中直到 \(i-1\) 的前缀划分为三组,每组的字符串相同。

所以说每组字符串的中的 aababc 的数量变成了 \(\frac{f_{i-1,1}}{3}\),\(\frac{f_{i-1,2}}{3}\) 和 \(\frac{f_{i-1,3}}{3}\)。

于是考虑将第一组的后面加一个 a,第二组加一个 b,第三组加一个 c。这样子我们就可以写出一个转移方程:

\[\begin{cases}f_{i,1}=\frac{f_{i-1,1}+3^m}{3}+\frac{2f_{i-1,1}}{3}\\f_{i,2}=\frac{f_{i-1,2}+f_{i-1,1}}{3}+\frac{2f_{i-1,2}}{3}\\f_{i,3}=\frac{f_{i-1,3}+f_{i-1,2}}{3}+\frac{2f_{i-1,3}}{3}\end{cases}
\]

整理一下得到以下转移:

\[f_{i,1}=f_{i-1,1}+3^{m-1},f_{i,2}=f_{i-1,2}+\frac{f_{i-1,1}}{3},f_{i,3}=f_{i-1,3}+\frac{f_{i-1,2}}{3}
\]

线性 DP 就没了。

有一个加强版就是说多组询问求任意子段的答案。注意到 \(f_{i}\) 只与 \(f_{i-1}\) 有关所以可以写成一个 \(4\times 4\) 的矩阵,然后用线段树维护矩阵乘积就好了。可能会算重,于是除掉一下就差不多了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51,MOD=1e9+7,INV3=333333336;
ll n,m,pw=1;
char ch[MAXN];
ll f[MAXN][3];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
int main()
{
n=read(),scanf("%s",ch+1);
for(register int i=1;i<=n;i++)
{
ch[i]=='?'?m++,pw=(li)pw*3%MOD:1;
}
for(register int i=1;i<=n;i++)
{
f[i][1]=f[i-1][1],f[i][2]=f[i-1][2],f[i][3]=f[i-1][3];
if(ch[i]=='a')
{
f[i][1]=(f[i][1]+pw)%MOD;
}
if(ch[i]=='b')
{
f[i][2]=(f[i][2]+f[i-1][1])%MOD;
}
if(ch[i]=='c')
{
f[i][3]=(f[i][3]+f[i-1][2])%MOD;
}
if(ch[i]=='?')
{
f[i][1]=(f[i][1]+(li)pw*INV3%MOD)%MOD;
f[i][2]=(f[i][2]+(li)f[i-1][1]*INV3)%MOD;
f[i][3]=(f[i][3]+(li)f[i-1][2]*INV3)%MOD;
}
}
printf("%d\n",f[n][3]);
}

CodeForces 1426F Number of Subsequences的更多相关文章

  1. Codeforces Round #674 (Div. 3) F. Number of Subsequences 题解(dp)

    题目链接 题目大意 给你一个长为d只包含字符'a','b','c','?' 的字符串,?可以变成a,b,c字符,假如有x个?字符,那么有\(3^x\)个字符串,求所有字符串种子序列包含多少个abc子序 ...

  2. codeforces Hill Number 数位dp

    http://www.codeforces.com/gym/100827/attachments Hill Number Time Limits:  5000 MS   Memory Limits: ...

  3. CodeForces 689D Friends and Subsequences (RMQ+二分)

    Friends and Subsequences 题目链接: http://acm.hust.edu.cn/vjudge/contest/121333#problem/H Description Mi ...

  4. CodeForces - 803F: Coprime Subsequences(莫比乌斯&容斥)

    Let's call a non-empty sequence of positive integers a1, a2... ak coprime if the greatest common div ...

  5. 【codeforces 803F】Coprime Subsequences

    [题目链接]:http://codeforces.com/contest/803/problem/F [题意] 给你一个序列; 问你这个序列里面有多少个子列; 且这个子列里面的所有数字互质; [题解] ...

  6. codeforces 27E Number With The Given Amount Of Divisors

    E. Number With The Given Amount Of Divisors time limit per test 2 seconds memory limit per test 256 ...

  7. Codeforces 27E. Number With The Given Amount Of Divisors (暴力)

    题目链接:http://codeforces.com/problemset/problem/27/E 暴力 //#pragma comment(linker, "/STACK:1024000 ...

  8. Codeforces 235E Number Challenge

    http://codeforces.com/contest/235/problem/E 远距离orz......rng_58 证明可以见这里(可能要FQ才能看到) 还是copy一下证明吧: 记 $$f ...

  9. CodeForces 1151E Number of Components

    题目链接:http://codeforces.com/problemset/problem/1151/E 题目大意: n个人排成一个序列,标号为 1~n,第 i 个人的学习成绩为 ai,现在要选出学习 ...

随机推荐

  1. 从一段 Dubbo 源码到 CPU 分支预测的一次探险之旅

    每个时代,都不会亏待会学习的人. 大家好,我是 yes. 这次本来是打算写一篇 RocketMQ 相关文章的,但是被插队了,我也是没想到的. 说来也是巧最近在看 Dubbo 源码,然后发现了一处很奇怪 ...

  2. Python-求序列长度和序列长度协议-len() __len__

    len() 求序列的长度 print(len("beimenchuixue")) print(len([1, 2, 3])) __len__ 对象中实现这个方法,则 len() 方 ...

  3. 配置hive的元数据到Mysql中

    在hive的安装目录下,进入conf目录,创建一个hive-site.xml文件 根据官方文档配置参数,拷贝数据到hive-site.xml文件中 https://cwiki.apache.org/c ...

  4. Raft 协议

    Paxos 存在的问题 Paxos 算法的描述偏学术化,缺失了很多细节,无法直接应用于工程领域.实际工程应用中的分布式算法大多是 Paxos 的变种,验证这些算法的正确性也成为了一个难题. 举个例子: ...

  5. java高级项目 jdbc与数据库连接数据库

    //图书管类 public class Book { private Integer id; private String b_name; private double b_price; privat ...

  6. Django Croppie

    下载 Django CroppieDjango Croppie django -croppie是一个简单集成croppie.js图像cropper到django项目的应用程序. 安装 安装与pip安装 ...

  7. 从面试角度学完 Kafka

    Kafka 是一个优秀的分布式消息中间件,许多系统中都会使用到 Kafka 来做消息通信.对分布式消息系统的了解和使用几乎成为一个后台开发人员必备的技能.今天码哥字节就从常见的 Kafka 面试题入手 ...

  8. set的运用 例题5-3 安迪的第一个字典(Andy's First Dictionary,Uva 10815)

    #include<bits/stdc++.h>using namespace std;set<string> dict;int main(){ string s, buf; w ...

  9. Jenkins+pytest+Allure搭建自动化测试

    持续集成(CONTINUOUS INTEGRATION) 在CI环境中,开发人员将会频繁地向主干提交代码.这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试流进行验证. 持续交付(CONTI ...

  10. 2020年9月程序员工资统计,平均14459元!你给程序员拖后腿了吗?https://jq.qq.com/?_wv=1027&k=JMPndqoM

    2020年9月全国招收程序员362409人.2020年9月全国程序员平均工资14459元,工资中位数12500元,其中95%的人的工资介于5250元到35000元. 工资与上个月持平,但是岗位有所增加 ...