题目描述
给定一个字符串
给定一个字符串,求有多少没有连续字母出现的不同子序列
字符串长度为(2 imes 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
",ans%mod);
return 0;
}