学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!
附上汇总贴:小猴编程C++ | 汇总-CSDN博客
【题目描述】
有一个字符串
s
s
s,取出
s
s
s的一个非空子序列,然后任意重排这个子序列的字符顺序,得到的新字符串中,有多少种不同的字符串?
例如,取字符串
a
a
b
aab
aab的长度为
1
1
1的子序列,只能得到
2
2
2种不同的字符串
a
a
a和
b
b
b;取长度为
2
2
2的子序列并重排,能得到
a
a
,
a
b
,
b
a
aa,ab,ba
aa,ab,ba这
3
3
3种不同的字符串;长度为
3
3
3的子序列是
a
a
b
aab
aab,经过重排可以得到
3
3
3个不同的字符串
a
a
b
,
a
b
a
,
b
a
a
aab,aba,baa
aab,aba,baa。
答案可能很大,你只需要输出答案模
998244353
998244353
998244353 的余数。
【输入】
1
1
1行,
1
1
1个字符串
s
s
s。
【输出】
1
1
1个整数,表示答案模
998244353
998244353
998244353 的余数。
【输入样例】
aab
【输出样例】
8
【代码详解】
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5005, mod = 998244353;
string st;
int n, s[27];
int c[N][N], dp[27][N];
int main()
{
cin >> st;
n = st.length();
for (int i=0; i<n; i++) s[st[i]-'a'+1]++; // 统计每个字母出现的次数
for (int i=0; i<=n; i++) { // 使用杨辉三角保存C(n,m)
c[i][0] = 1; // C(0,0)为1
for (int j=1; j<=i; j++) {
c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
}
}
dp[0][0] = 1; // 不选任何字母的状态
int m = 0; // 优化时间
for (int i=1; i<=26; i++) {
m += s[i]; // m是不会超过前i个字母的总和的
for (int j=0; j<=m; j++) {
for (int k=0; k<=s[i] && k<=j; k++) {
dp[i][j] = (dp[i][j]+1ll*dp[i-1][j-k]*c[j][k]) % mod; // 乘法会超过int,所以要1ll*
}
}
}
int ans = 0;
for (int i=1; i<=n; i++) { // 枚举从1到n
ans = (ans + dp[26][i]) % mod;
}
cout << ans << endl;
return 0;
}
【运行结果】
aab
8