专栏文章
题解:AT_abc433_f [ABC433F] 1122 Subsequence 2
AT_abc433_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min1byej
- 此快照首次捕获于
- 2025/12/01 18:57 3 个月前
- 此快照最后确认于
- 2025/12/01 18:57 3 个月前
1122 Subsequence 2
题目大意
给定一个由数字组成的字符串 。
现给出对“ 字符串”的定义:对于某字符串 ,当其满足以下条件时,就被成为“ 字符串”。
- 是一个由数字组成的非空字符串。
- (字符串 的长度) 为偶数。
- 字符串 中第 个字符至第 个字符均为同一数字。 字符串 中从第 个字符到第 个字符均为 的第 个字符(表示的)数字加 形成的字符。
求字符串 中所有(不一定是连续的)子序列中为“ 字符串”的数量,结果对 取模。
若两个子序列来自不同位置,则即使其字符串内容相同,也应分别计数。
思路分析
考虑枚举 中满足条件的子序列的左半段最后一个字符的位置(第 个字符)。
假设这是知道的唯一条件,即设该位置字符必选,考虑在这种情况下计算符合条件的子序列数量。
假设当前答案子序列的左半段最后一个字符的位置(在原字符串中)为 ,则该字符为 。
记 的左侧(包含 )与 相同的字符有 个, 的右侧与 相同的字符有 个,在 的左、右侧都会分别选取 个字符(则有 ,换句话说,就是 )。
因此, 的左侧(包含 )需要在 (因为第 个字符必选)个字符中选 个, 的右侧需要在 个字符中选 个,因此总方案就有 种。
则以 为答案左半段最后一个字符时,对总数的贡献为:
大家看着这个转移可能会很迷惑,因此在此做出解释:
- 第一步只变了一处,依靠的是 。
- 第二步注意到式子被表现成了 的形式,因此根据 范德蒙恒等式,可以化为 的形式。
最后就很简单了,逆元预处理阶乘后借助公式求解组合数即可。
代码详解
CPP#include<bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
string s;
unordered_map<char,int> frt,bck; //当前字符在其位置前、后出现的次数
int n,fac[2000005]={1},inv[2000005],ans;
int pows(int a,int b,int p){
int now=1;
while(b>0){
if(b&1) now=now*a%p;
a=a*a%p;
b>>=1;
}
return now;
}
//利用预处理数组计算组合数
int cxy(int x,int y){
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>s;
n=s.size();
s=" "+s;
//逆元预处理
for(int i=1;i<=2000000;i++) fac[i]=fac[i-1]*i%mod;
inv[2000000]=pows(fac[2000000],mod-2,mod);
for(int i=1999999;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
//先假设所有字符都在答案后半段
for(int i=1;i<=n;i++) bck[s[i]]++;
//O(|S|)计算答案
for(int i=1;i<=n;i++){
frt[s[i]]++,bck[s[i]]--;
ans=(ans+cxy(frt[s[i]]+bck[s[i]+1]-1,frt[s[i]]))%mod; //公式解释见上文
}
cout<<ans;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...