题目大意
有一个长度为 n ( n < = 2 ∗ 1 0 5 ) n(n<=2*10^{5}) n(n<=2∗105)的字符串,可以选择一些位置(这些位置不能相邻)组成新的子串(不能调换字符的相对位置),问一共可以选出多少种不同的子串,输出答案对 1 e 9 + 7 1e9+7 1e9+7取模
思考
一般子序列的题都要靠dp解决?
设
f
[
i
]
f[i]
f[i]为第
i
i
i个位置必须选的合法答案数量。
第一种转移比较显然:
f
[
i
]
=
f
[
i
]
+
f
[
j
]
,
(
j
=
=
0
∣
∣
j
<
i
−
1
)
,
其
中
f
[
0
]
=
1
f[i]=f[i]+f[j],(j==0||j<i-1),其中f[0]=1
f[i]=f[i]+f[j],(j==0∣∣j<i−1),其中f[0]=1
第二种:
当
s
[
j
]
=
=
s
[
i
]
s[j]==s[i]
s[j]==s[i]时,此时小于j的可以转移到j的位置都不再能转移到
i
i
i,但是
j
−
1
j-1
j−1不能转移到
j
j
j,所以
j
−
1
j-1
j−1可以转移到
i
i
i.
于是总的转移其实是一段前缀和。所以我们有一个严格线性的做法(记录一些前缀和)。
但是由于字符集很小,所以我们其实可以直接暴力转移
关于暴力算法的复杂度
假设字符集大小为
l
(
l
<
=
26
)
l(l<=26)
l(l<=26),每个字符出现
p
p
p次,
(
l
∗
p
=
=
n
)
(l*p==n)
(l∗p==n).
那么我们考虑字符的出现方式,如果每个字符的出现长度为
a
a
a,一共出现了
b
b
b次
(
a
∗
b
=
=
p
)
(a*b==p)
(a∗b==p)。那么需要循环多于一次的位置总共的复杂度就是
b
∗
l
∗
a
∗
l
=
=
n
∗
l
b*l*a*l==n*l
b∗l∗a∗l==n∗l,鉴于l很小,所以暴力算法可以直接通过。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int mod=1e9+7;
char s[maxn];
int n,f[maxn],ans;
inline int ad(int a,int b){
return a+b>=mod?a+b-mod:a+b;
}
signed main(int argc,char* argv[]){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>s+1;
n=strlen(s+1);
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=i-1;j>=0;j--){
if((j==0)||(j<i-1)){f[i]=ad(f[i],f[j]);}
if(s[j]==s[i]){
if(j>1)f[i]=ad(f[j-1],f[i]);
break;
}
}
ans=ad(ans,f[i]);
}
cout<<ans<<endl;
return 0;
}