这题真的啥也不会……
@Yubai赛时随手切了,Orz
留个坑,自动机啥也不会……
这里其实有个很套路的DP柿子 \(dp[i][j] = dp[i-1][j]+dp[i-1][j-1]\)
即为分别考虑位置i上的数选或不选所造成的贡献
但是这里还有个重复情况需要考虑
1 2 3 4 5 6 7 8
a b c d e a b c
这里a与位置2上的b和位置7上的b会重复造成贡献(重复的前缀)
所以需要减去,令\(p[i]\)记录上一个s[i]出现的位置
所以最终方程为
注意这里有个减一,因为是减去前缀的重复
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3050
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, l, cnt[N];
const ll p=998244353;
char s[N];
namespace force{
ll ans;
const ll base=131;
unordered_map<ll, bool> mp;
void dfs(int u, int l, ll h) {
//cout<<"dfs "<<u<<' '<<l<<endl;
if (l<=0) {
//cout<<h<<endl;
if (!mp[h]) {++ans; mp[h]=1;}
return ;
}
if (u>n) return ;
dfs(u+1, l, h);
dfs(u+1, l-1, (h*base+s[u])%p);
}
void solve() {
//for (int i=0; i<=n; ++i) cout<<cnt[i]<<' '; cout<<endl;
dfs(1, l, 0);
printf("%lld\n", ans%p);
exit(0);
}
}
namespace task{
ll lst[26], p[N], dp[N][N];
const ll mod=998244353;
void solve() {
for (int i=1; i<=n; ++i) {
p[i]=lst[s[i]-'a'];
lst[s[i]-'a']=i;
}
dp[0][0]=1;
for (int i=1; i<=n; ++i)
for (int j=0; j<=l; ++j)
dp[i][j] = (dp[i-1][j]+dp[i-1][j-1]-(p[i]?dp[p[i]-1][j-1]:0))%mod;
printf("%lld\n", (dp[n][l]+mod)%mod);
exit(0);
}
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
scanf("%s%d", s+1, &l); n=strlen(s+1);
if (n==l) {puts("1"); return 0;}
for (int i=2; i<=n; ++i) if (s[i]!=s[i-1]) goto jump;
puts("1"); return 0; jump:
for (int i=1; i<=n; ++i) ++cnt[s[i]-'a'];
if (l==1) {
int ans=0;
for (int i=0; i<26; ++i) if (cnt[i]) ++ans;
printf("%d\n", ans); return 0;
}
//force::solve();
task::solve();
return 0;
}