CF1648C Tyler and Strings 题解
题目大意
给定一个长度为 的序列 和长度为 的序列 。现在你需要将序列 进行重排列,求字典序小于 的不同种类。对 取余。
不同种类的定义为至少存在一位不同。
。
题目解析
不难想到我们可以枚举 ,计算 并且 的种类。
显然发现从 开始就是没有限制的了。
考虑当前有 个数字,开个桶,令数字 有 个。
令总方案数为
这时如果去掉一个数字 ,那么这时的方案数量为
也就是说
然后我们考虑计算 并且 的种类。
这也就是相当于去掉数字 的答案和。
新增的答案等于
也就是
这样开个树状数组维护一下 的前缀和即可。
注意以上的做法没有考虑到当 并且存在一种方法使得 的方法。
核心代码:
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具