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);
} 
posted @ 2021-09-05 00:09  zlc0405  阅读(468)  评论(0编辑  收藏  举报