题意:
给定一个只包含“abc?”的字符串,其中’?'可以替换为abc的任意一种。
问对于所有可能的串,子序列abc的总和是多少。
答案对1e9+7取模。
数据范围:n<=2e5
解法:
三 元 组 统 计 的 套 路 : 枚 举 中 间 的 b , 统 计 两 端 的 a 和 c 计 算 贡 献 。 三元组统计的套路:枚举中间的b,统计两端的a和c计算贡献。 三元组统计的套路:枚举中间的b,统计两端的a和c计算贡献。
假 设 左 边 有 x 个 ′ a ′ , y 个 ′ ? ′ 。 假设左边有x个'a',y个'?'。 假设左边有x个′a′,y个′?′。
假 设 i 个 变 成 a , 那 么 y − i 个 就 变 成 b / c , 方 案 数 为 C ( y , i ) ∗ 2 y − i 假设i个变成a,那么y-i个就变成b/c,方案数为C(y,i)*2^{y-i} 假设i个变成a,那么y−i个就变成b/c,方案数为C(y,i)∗2y−i
加 上 固 定 的 x 个 , 那 么 可 能 的 a 的 个 数 总 为 : ∑ i = 0 y C ( y , i ) ∗ 2 y − i ∗ ( x + i ) 加上固定的x个,那么可能的a的个数总为:\sum_{i=0}^yC(y,i)*2^{y-i}*(x+i) 加上固定的x个,那么可能的a的个数总为:∑i=0yC(y,i)∗2y−i∗(x+i)
将 式 子 拆 开 变 为 : 将式子拆开变为: 将式子拆开变为:
∑ i = 0 y C ( y , i ) ∗ 2 y − i ∗ i + ∑ i = 0 y C ( y , i ) ∗ 2 y − i ∗ x \sum_{i=0}^yC(y,i)*2^{y-i}*i+\sum_{i=0}^yC(y,i)*2^{y-i}*x ∑i=0yC(y,i)∗2y−i∗i+∑i=0yC(y,i)∗2y−i∗x
= ∑ i = 0 y C ( y , i ) ∗ 2 y − i ∗ i + ( 1 + 2 ) y ∗ x =\sum_{i=0}^yC(y,i)*2^{y-i}*i+(1+2)^{y}*x =∑i=0yC(y,i)∗2y−i∗i+(1+2)y∗x
= ∑ i = 0 y C ( y , i ) ∗ 2 y − i ∗ i + 3 y ∗ x =\sum_{i=0}^yC(y,i)*2^{y-i}*i+3^{y}*x =∑i=0yC(y,i)∗2y−i∗i+3y∗x
因 为 C ( n , m ) = n ! m ! ∗ ( n − m ) ! , 因 此 式 子 变 为 因为C(n,m)=\frac {n!}{m!*(n-m)!},因此式子变为 因为C(n,m)=m!∗(n−m)!n!,因此式子变为
∑ i = 0 y y ! i ! ∗ ( y − i ) ! ∗ 2 y − i ∗ i + 3 y ∗ x \sum_{i=0}^y \frac {y!}{i!*(y-i)!}*2^{y-i}*i+3^{y}*x ∑i=0yi!∗(y−i)!y!∗2y−i∗i+3y∗x
= ∑ i = 0 y y ! ( i − 1 ) ! ∗ ( y − i ) ! ∗ 2 y − i + 3 y ∗ x =\sum_{i=0}^y \frac {y!}{(i-1)!*(y-i)!}*2^{y-i}+3^{y}*x =∑i=0y(i−1)!∗(y−i)!y!∗2y−i+3y∗x
= y ∗ ∑ i = 0 y ( y − 1 ) ! ( i − 1 ) ! ∗ ( y − i ) ! ∗ 2 y − i + 3 y ∗ x =y*\sum_{i=0}^y \frac {(y-1)!}{(i-1)!*(y-i)!}*2^{y-i}+3^{y}*x =y∗∑i=0y(i−1)!∗(y−i)!(y−1)!∗2y−i+3y∗x
= y ∗ ∑ i = 0 y ( y − 1 ) ! ( i − 1 ) ! ∗ ( y − i ) ! ∗ 2 y − i + 3 y ∗ x =y*\sum_{i=0}^y \frac {(y-1)!}{(i-1)!*(y-i)!}*2^{y-i}+3^{y}*x =y∗∑i=0y(i−1)!∗(y−i)!(y−1)!∗2y−i+3y∗x
= y ∗ ∑ i = 0 y C ( y − 1 , y − i ) ∗ 2 y − i + 3 y ∗ x =y*\sum_{i=0}^yC(y-1,y-i)*2^{y-i}+3^{y}*x =y∗∑i=0yC(y−1,y−i)∗2y−i+3y∗x
= y ∗ ∑ i = 0 y C ( y − 1 , y − i ) ∗ 2 y − i + 3 y ∗ x =y*\sum_{i=0}^yC(y-1,y-i)*2^{y-i}+3^{y}*x =y∗∑i=0yC(y−1,y−i)∗2y−i+3y∗x
左 边 当 i = 0 时 = 0 , 那 么 下 标 可 以 改 为 从 i = 1 开 始 左边当i=0时=0,那么下标可以改为从i=1开始 左边当i=0时=0,那么下标可以改为从i=1开始
= y ∗ ∑ i = 1 y C ( y − 1 , y − i ) ∗ 2 y − i + 3 y ∗ x =y*\sum_{i=1}^yC(y-1,y-i)*2^{y-i}+3^{y}*x =y∗∑i=1yC(y−1,y−i)∗2y−i+3y∗x
y − i 可 以 替 换 为 i , 因 为 是 对 称 的 y-i可以替换为i,因为是对称的 y−i可以替换为i,因为是对称的
= y ∗ ∑ i = 0 y − 1 C ( y − 1 , i ) ∗ 2 i + 3 y ∗ x =y*\sum_{i=0}^{y-1}C(y-1,i)*2^i+3^y*x =y∗∑i=0y−1C(y−1,i)∗2i+3y∗x
= y ∗ ( 2 + 1 ) y − 1 + 3 y ∗ x =y*(2+1)^{y-1}+3^y*x =y∗(2+1)y−1+3y∗x
= 3 y − 1 ∗ y + 3 y ∗ x =3^{y-1}*y+3^y*x =3y−1∗y+3y∗x
预 处 理 p o w ( 3 ) 即 可 预处理pow(3)即可 预处理pow(3)即可
上 面 计 算 的 是 左 边 的 数 量 , 右 边 一 样 的 上面计算的是左边的数量,右边一样的 上面计算的是左边的数量,右边一样的
参 考 : h t t p s : / / w w w . l u o g u . c o m . c n / b l o g / Z i g Z a g K m p / C F 1426 F − s o l u t i o n 参考:https://www.luogu.com.cn/blog/ZigZagKmp/CF1426F-solution 参考:https://www.luogu.com.cn/blog/ZigZagKmp/CF1426F−solution
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
const int mod=1e9+7;
char s[maxm];
int p3[maxm];
int lx[maxm],rx[maxm];
int ly[maxm],ry[maxm];
int n;
void init(){
p3[0]=1;
for(int i=1;i<maxm;i++)p3[i]=1ll*p3[i-1]*3%mod;
}
signed main(){
init();
cin>>n;
scanf("%s",s+1);
for(int i=1;i<=n;i++){
lx[i]=lx[i-1];
ly[i]=ly[i-1];
if(s[i]=='a')lx[i]++;
else if(s[i]=='?')ly[i]++;
}
for(int i=n;i>=1;i--){
rx[i]=rx[i+1];
ry[i]=ry[i+1];
if(s[i]=='c')rx[i]++;
else if(s[i]=='?')ry[i]++;
}
int ans=0;
for(int i=1;i<=n;i++){
if(s[i]=='b'||s[i]=='?'){
int L=0;
L+=p3[ly[i-1]]*lx[i-1]%mod;
if(ly[i-1])L+=p3[ly[i-1]-1]*ly[i-1]%mod;
int R=0;
R+=p3[ry[i+1]]*rx[i+1]%mod;
if(ry[i+1])R+=p3[ry[i+1]-1]*ry[i+1]%mod;
ans=(ans+L*R)%mod;
}
}
cout<<ans<<endl;
return 0;
}