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;
}

posted @ 2021-08-15 12:59  lzylzy/kk  阅读(101)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end