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;
}

浙公网安备 33010602011771号