ABC214F substrings
题目描述
给定一个字符串
给定一个字符串,求有多少没有连续字母出现的不同子序列
字符串长度为\(2 \times 10^5\)
题解
看起来像是dp题,于是列个式子
我们先不考虑重复的问题
设\(f[i]\)表示以i为结尾且字母\(i\)必须被选择的方案数
有\(f[i]=\sum f[j],1<=j<=i-1\)
接下来想如果出现重复字符怎么办
我们发现,对于\(s[i]=s[j]\),即字符相等时,任何\(j\)以前的答案都无需再次统计
因为我们可以认为用\(i\)位置上的字符替换\(j\)位置,则\(f[j]\)就包括从1到j的所有答案
关于边界,f[0]=1
加上一些其他的小判断即可,不知道为什么官方题解就没这么多事情qwq
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<cstring>
using namespace std;
const int inf=0x7fffffff;
typedef long long ll;
#define maxn 200009
char s[maxn];
int f[maxn];
#define mod 1000000007
signed main()
{
scanf("%s",s+1);
int n=strlen(s+1);
f[1]=1,f[0]=1;
for(int i=1;i<=n;i++)
{
bool flag=0;
if(s[i]==s[i-1])flag=1;
if(s[i]==s[i-1]&&i-2==0)continue;//这个是前两个字符一样,第二个字符答案为0
for(int j=i-2;j>=0;j--)
{
f[i]=(f[j]+f[i])%mod;
if(s[i]==s[j]&&j==1)break;
if(s[i]==s[j+1]||flag)break;//如果连续两个一样,光统计上一个字符的前一位答案即可
}
//cout<<f[i]<<endl;
}
ll ans=0;
for(int i=1;i<=n;i++)ans=(ans+f[i])%mod;
printf("%lld\n",ans%mod);
return 0;
}