最近的 ABC 题目质量都好高啊,最后两题都吊打我。
不过 ABC214D 撞题 CF915F 喽。
题意:
给定长度为 \(n\) 的字符串,求本质不同的子序列数模 \(10^9+7\)。一个子序列必须满足不存在两个位置在原串中相邻。
Data range:\(n \le 2\,\times\,10^5\)
分析:
感谢 ABC 教会我一种新的 dp 科技。
第一眼可能是字符串算法,但是我们想想 kmp,trie,acam,sa,hash 似乎都解决不了这个问题()。
所以考虑 \(dp\),设 \(f(i)\) 为 \(s_1\sim s_i\) 里,以第 \(i\) 位结尾的,新产生的本质不同子序列个数。特殊地,令 \(f(0)=0\)。
我们发现,如果 \(s_i = s_{i-1}\),那么如果 \(i=2\),则 \(f(i)=0\);否则 \(f(i)=f(i-2)\)。
然后考虑 \(s_i \neq s_{i-1}\) 的情况,假如前面没有一个 \(s_k=s_i\),那么 \(f(i)=\sum_{j=0}^{i-2}f(j)\);否则,设 \(last\) 是前面第一个和 \(a_i\) 相等的位置 \(k\)(\(k<i-1)\),那么答案应该是 \(\sum_{j=last}^{i-2}f(j)\),特殊地,如果 \(k \neq 1\),那么还应该加上 \(f(k-1)\)。
那么上面的式子都可以用前缀和维护。我们发现上面的流程都要特判使得不加上 \(f(0)\) 这个东西,方便起见我们设 \(f(0)=0\),然后 \(pre\) 数组代表前缀和,\(pre_0=1\) 就行了。
最后我们思考一下为什么要对 \(f(0)\) 搞特殊。因为对于长度大于 \(0\) 的子序列,它下一个不能相邻。但如果本来是空串,它可以直接下一个选择 \(s_1\),没有不相邻的要求。
最后输出 \(\sum_{i=1}^nf(i)\) 就行了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const int MAXN=2e5+10,mod=1e9+7;
char s[MAXN];
int n,f[MAXN],pre[MAXN],last[MAXN];
int main(){
cin>>(s+1);
n=strlen(s+1);
pre[0]=1;
rep(i,1,n){
if(i==1){
f[1]=1;
pre[1]=2;
continue;
}
if(s[i]==s[i-1]){
f[i]=f[i-2];
}else{
f[i]=(pre[i-2]-pre[last[s[i]-'a'+1]-1]+mod)%mod;
f[i]=(f[i]+f[last[s[i]-'a'+1]-1])%mod;
}
pre[i]=(pre[i-1]+f[i])%mod;
last[s[i-1]-'a'+1]=i-1;
}
printf("%d",(pre[n]-1+mod)%mod);
return 0;
}