GYM103069A.Namomo Subsequence(EC-FINAL)
询问一个序列里有多少个Namomo子序列
字符集60。
考虑枚举momo。
从右往左遍历。
\(f(i,j,0)\)表示当前形如\((i,j,i,j)\)的组数。
\(f(i,j,1)\)表示当前形如\((j,i,j)\)的组数。
\(f(i,j,2)\)表示当前形如\((i,j)\)的组数。
对于当前位置\(i\)。
枚举\(j\),\(f(i,j,0)\)可以继承自\(f(i,j,1)\)。
\(f(i,j,2)\)可以继承自前面\(j\)的数量。
\(f(j,i,1)\)可以继承自\(f(j,i,2)\)的数量。
然后再对每一组\((i,j)\),找前面不等于\((i,j)\)的组数。
算完这一步之后把当前的\(f(i,j,0)\)清空,因为已经被算过了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
const int mod=998244353;
typedef long long ll;
map<char,int> mp;
ll c[maxn][70];//前缀和数组
ll f[70][70][3],a[maxn];
ll qpow (ll a,ll b) {
ll ans=1;
ll base=a;
while (b) {
if (b&1) ans=(ans*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return ans;
}
int main () {
ll ny=qpow(2,mod-2);
for (int i=0;i<26;i++) mp[i+'a']=i+1;
for (int i=0;i<26;i++) mp[i+'A']=26+i+1;
for (int i=0;i<=9;i++) mp[i+'0']=52+i+1;
string s;
cin>>s;
int n=s.size();
for (int i=1;i<=n;i++) a[i]=mp[s[i-1]];
for (int i=1;i<=n;i++) {
for (int j=1;j<=62;j++) {
c[i][j]=c[i-1][j];
}
c[i][a[i]]++;
}
ll ans=0;
for (int i=n;i>=1;i--) {
ll sum=0;
ll tt=0;
for (int j=1;j<=62;j++) sum+=c[i-1][j];
for (int j=1;j<=62;j++) tt+=c[i-1][j]*(c[i-1][j]-1+mod)%mod*ny%mod,tt%=mod;
for (int j=1;j<=62;j++) {
if (a[i]==j) continue;
f[a[i]][j][0]+=f[a[i]][j][1];f[a[i]][j][0]%=mod;
f[a[i]][j][2]+=c[n][j]-c[i-1][j];f[a[i]][j][2]%=mod;
f[j][a[i]][1]+=f[j][a[i]][2];f[j][a[i]][1]%=mod;
ans+=1ll*f[a[i]][j][0]*(sum%mod*(sum-1+mod)%mod*ny%mod-tt+mod-c[i-1][j]*(sum-c[i-1][j])%mod+mod-c[i-1][a[i]]*(sum-c[i-1][a[i]])%mod+c[i-1][j]*c[i-1][a[i]]%mod+mod)%mod;
f[a[i]][j][0]=0;
ans%=mod;
}
}
printf("%lld\n",ans);
}