[CF1753C]Wish I Knew How to Sort
做题时间:2022.10.25
给定一个长度为 的01序列 和一种操作,你需要用这种操作将序列从小到大排序。操作为:等概率随机选择两个位置 ,若 ,则交换 和 (当 ,交换失败也算一次操作)
求出执行操作的期望次数,对 取模
第一行一个整数 表示数据组数
每组数据第一行一个整数 表示序列长度
接下来一行 个整数表示序列
对于每组数据,输出一行一个整数表示答案
期望、概率
最终单调不降的目标序列肯定是 00...00111...111
,交换过程就是以中间的 和 为分界线,左边的 全部移动到右边,右边的 全部移动到左边,根据期望线性性质,我们可以单独考虑每一次操作,最后将每次操作的期望值加起来即可。
设当前分界线左边有 个 ,则分界线右边会有 个 ,交换一次左边的 和右边的 的概率为:
而期望是概率的倒数,因此最终我们要求的便是:
其中 是一开始分界线左边的 数量(右边的 数量)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+50; const ll mod=998244353; int n,a[N],cnt,k,t; ll Pow(ll a,ll b) { ll ans=1ll,base=a%mod; while(b){ if(b&1) ans*=base,ans%=mod; base*=base,base%=mod; b>>=1; } return ans; } void Wish() { cnt=0,k=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),cnt+=(a[i]==0);//计算分界线 for(int i=1;i<=cnt;i++){ if(a[i]) k++; } ll ans=0; for(int i=1;i<=k;i++){//计算答案 ans+=1ll*n*(n-1)%mod*Pow(2ll*i*i,mod-2)%mod; ans%=mod; } printf("%lld\n",ans); } int main() { scanf("%d",&t); while(t--) Wish(); return 0; }
本文作者:lxzy
本文链接:https://www.cnblogs.com/Unlimited-Chan/p/16823701.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步