AT_abc234_f

思路

一眼 Dp,我们定义状态 \(f_{i,j}\) 为用了前 \(i\) 个字符,组成的长度为 \(j\) 的方案数,这里的 \(i\) 个字符是指 a,b,c,d,e 这样的字符。那么我们对于一个字符 \(c\) 我们自然有 \(j-1\) 个空可以插入然后我们一共需要插入 \(k\)\(c\) 所以我们可得状态转移方程 \(f_{i,j }=f_{i-1,j-k}\times \binom{j}{k}\) 这里我们只需要预处理出来组合技术即可。

代码

#include <bits/stdc++.h>
#define IOS std::ios::sync_with_stdio(fasle);cin.tie(NULL);cout.tie(NULL)
#define int long long
#define ri register int
#define rep(i,x,y) for(ri i=x;i<=y;i++)
#define rep1(i,x,y) for(ri i=x;i>=y;i--)
#define il inline
#define fire signed
#define pai(a,x,y) sort(a+x,a+y+1)
using namespace std ;
const int N=5e3+10,mod=998244353;
il int qmi(int a,int b) {
	int res=1;
	while(b) {
		if(b&1) res=(res*a)%mod;
		a=a*a;
		a%=mod;
		b>>=1;
	}
	return res;
}
void read(int &x) {
	x=false;
	ri f=1;
	char c=getchar();
	while(c>'9'||c<'0') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c-'0'<=9&&c>='0') {
		x=x*10+c-'0';
		c=getchar();
	}
	x*=f;
}
void print(int x) {
	if(x>=10) print(x/10);
	putchar(x%10+'0');
}
#define gcd(x,y) __gcd(x,y)
#define lcm(x,y) x*y/gcd(x,y)
int inv[1000000+11],fac[1000011];
string s;
int f[N][30];
int C(int j,int k) {
	if(j<k) return 0;
	return ((fac[j]*inv[k])%mod*inv[j-k])%mod;
}
int t[30];
fire main() {
	cin>>s;
	int l=s.size();
	fac[0]=1;
	rep(i,1,1000000) fac[i]=(fac[i-1]*i)%mod;
	inv[1000000]=qmi(fac[1000000],mod-2);
	rep1(i,1000000-1,0) inv[i]=inv[i+1]*(i+1)%mod;
	rep(i,0,l-1) t[s[i]-'a'+1]++;
	f[0][0]=1;
	rep(j,0,l) rep(i,1,26) rep(k,0,min(t[i],j)) (f[j][i]+=(f[j-k][i-1]*C(j,k)%mod))%=mod;
	int res=0;
	rep(i,1,l) {
		res=(res+f[i][26])%mod;
	}
	print(res);
	return false;
}

posted @ 2024-01-31 11:49  highkj  阅读(6)  评论(0)    收藏  举报