[题解]AT_abc299_f [ABC299F] Square Subsequence
思路
首先先考虑弱化版怎么做,即如何求本质不同子序列数量。
不妨定义 在前 位中选,且以 结尾的本质不同子序列数量。
显然,有(其中 表示在 之后,第一次出现 的位置):
本题中的 是由两个 拼接而成,所以考虑枚举两个 的起始位置 。
在这里定义 表示两个 分别以 结尾的本质不同子序列数量。
再枚举一下两个 倒数第二个字符的位置,记作 ,并且枚举这个字符 。
那么,如果想使 继续延伸,那么,必须使新扩展的字符相同。因此,记 。
根据上述求本质不同子序列数量的状态转移方程,可得:
在统计答案的时候,不能直接将所有 加起来,这样会导致重复计算。所以,我们令 取最前面的字符。
Code
#include <bits/stdc++.h>
#define int long long
#define re register
using namespace std;
const int N = 110,mod = 998244353;
int n,ans;
int nxt[N][N],dp[N][N];
string s;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> s;
n = s.length();
s = ' ' + s;
for (re char c = 'a';c <= 'z';c++) nxt[n][c - 'a'] = n + 1;//预处理 nxt
for (re int i = n - 1;~i;i--){
for (re char c = 'a';c <= 'z';c++) nxt[i][c - 'a'] = nxt[i + 1][c - 'a'];
nxt[i][s[i + 1] - 'a'] = i + 1;
}
for (re int j = 2;j <= n;j++){
int i = nxt[0][s[j] - 'a'];
if (i >= j) continue;
memset(dp,0,sizeof(dp));
dp[i][j] = 1;//i,j 显然合法,贡献为 1
for (re int l = 1;l <= n;l++){
for (re int r = l + 1;r <= n;r++){
for (re char c = 'a';c <= 'z';c++){
int nl = nxt[l][c - 'a'];
int nr = nxt[r][c - 'a'];
if (nl >= r || nr > n) continue;
dp[nl][nr] = (dp[nl][nr] + dp[l][r]) % mod;
}
}
}
for (re int l = 1;l <= n;l++){
for (re int r = l + 1;r <= n;r++){
if (nxt[l][s[j] - 'a'] == j) ans = (ans + dp[l][r]) % mod;//要取最前面的
}
}
}
printf("%lld",ans);
return 0;
}
作者:WaterSun
出处:https://www.cnblogs.com/WaterSun/p/18262942
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】