CF1648C Tyler and Strings 题解

可能更好的阅读体验

题目传送门

题目大意

给定一个长度为 n 的序列 a 和长度为 m 的序列 b。现在你需要将序列 a 进行重排列,求字典序小于 b 的不同种类。对 998244353 取余。
不同种类的定义为至少存在一位不同。
n,m2×105,1ai,bi2×105

题目解析

不难想到我们可以枚举 k,计算 j[1,k1],aj=bj 并且 ak<bk 的种类。
显然发现从 i+2 开始就是没有限制的了。

考虑当前有 n 个数字,开个桶,令数字 iti 个。
令总方案数为 now=n!ti!
这时如果去掉一个数字 k,那么这时的方案数量为 now=(n1)!ikti!×(tk1)!
也就是说 now=now×tkn
然后我们考虑计算 j[1,k1],aj=bj 并且 ak<bk 的种类。
这也就是相当于去掉数字 1,2,,bk 的答案和。
新增的答案等于 i=1bk1now×tin
也就是 now×i1bk1n

这样开个树状数组维护一下 ti 的前缀和即可。

注意以上的做法没有考虑到当 n<m 并且存在一种方法使得 i[1,n],ai=bi 的方法。

核心代码:

int n,m,a[maxn],b[maxn],c[maxn],t[maxn];
#define lowbit(x) (x&-x)
void add(int x,int y){ while(x<=N) c[x]+=y,x+=lowbit(x); return; }
int find(int x){ int sum=0; while(x) sum+=c[x],x-=lowbit(x); return sum; }
ll fpow(ll x,ll y){
ll res=1,tmp=x%MOD; while(y){ if(y&1) res=res*tmp%MOD; y>>=1; tmp=tmp*tmp%MOD; } return res;
}
ll fact[maxn],inv[maxn],now,ans,tmp;
void init(){
int i; fact[0]=inv[0]=1; for(i=1;i<=N;i++) fact[i]=fact[i-1]*i%MOD; inv[N]=fpow(fact[N],MOD-2);
for(i=N-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%MOD; now=fact[n];
for(i=1;i<=n;i++) t[a[i]]++; for(i=1;i<=N;i++) add(i,t[i]),now=now*inv[t[i]]%MOD; return;
}
int main(){
n=read(); m=read(); int i; for(i=1;i<=n;i++) a[i]=read(); for(i=1;i<=m;i++) b[i]=read(); init();
for(i=1;i<=n;i++){
if(i>m) break; if(i==n&&n<m&&t[b[i]]) ans++;
tmp=fpow(n-i+1,MOD-2); ans+=now*tmp%MOD*find(b[i]-1)%MOD; ans%=MOD;
if(t[b[i]]){ now=now*tmp%MOD*t[b[i]]%MOD; t[b[i]]--; add(b[i],-1); } else break;
} print(ans%MOD); return 0;
}
posted @   jiangtaizhe001  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示