题目大意

\(T\)(\(T\leq10^5\))组询问

每次给出\(n,m,l,r\),和\(n\)个数\(a_1,a_2,...,a_n\),要找出\(m\)个可重复的在区间\([l,r]\)的数,使\(a_1,a_2,...,a_n\)和选出的\(m\)个数组成的序列期望随机排序得到升序序列的次数最多

输出序列最多期望随机排序几轮,模998244353

\(n\leq2\times10^5,\sum n\leq2\times10^6,m\leq10^7,a_i\leq10^9\)

题解

假设选出\(m\)个数后,一轮随机排序得到升序序列的概率为\(p\)

那么就相当于一轮随机排序期望得到\(p\)个升序序列

题目想要一个升序序列,那么期望\(\frac{1}{p}\)轮随机排序后得到一个升序序列

问题转化为求一轮随机排序后得到升序序列的概率

可以直接用\(\frac{合法方案数}{总方案数}\)算

长度为\(n+m\)的序列的总方案数是\((n+m)!\)

至于合法方案数,可以看成将序列排序后,交换相等的数得到的序列数,那么设值为\(i\)的数出现了\(b_i\)次,就有合法方案数=\(\sum b_i!\)

现在要最大化\(\frac{1}{\frac{\sum b_i!}{(n+m)!}}\),相当于是最小化\(\sum b_i!\)

发现尽量将\(m\)个数放到出现次数较小的值会更优

因为假设有两个值\(x,y\),\(b_x>b_y\),则有新加入一个\(=x\)的值,会让答案乘上\(b_x+1\),而如果新加入\(=y\)的值,就会使答案乘上\(b_y+1\),取\(y\)会更优

那么就可以选\(m\)次区间\([l,r]\)中出现次数最少的数

但是\(m\)比较大,考虑另一种统计方式

二分一个值\(k\),将出现次数少于\(k\)的值取至出现次数等于\(k\),判断够不够

因为\(n\)总共只有\(2\times10^6\),所以一个\(log\)能过

并不会不用二分的方法

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 200017
#define LL long long
#define D double
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int n,m,l,r,fac[maxn+10000000],ny[maxn+10000000],s1[maxn],tp1,s2[maxn],tp2,ans,num;
const LL mod=998244353;
int mul(int x,int y){int res=1;while(y){if(y&1)res=(LL)res*x%mod;x=(LL)x*x%mod,y>>=1;}return res;}
signed main()
{
fac[0]=1;int tm=0;
rep(i,1,maxn-17+10000000)fac[i]=(LL)fac[i-1]*i%mod;
ny[maxn-17+10000000]=mul(fac[maxn-17+10000000],mod-2);
dwn(i,maxn-18+10000000,0)ny[i]=(LL)ny[i+1]*(i+1)%mod;
int t=read();
while(t--)
{
n=read(),m=read(),l=read(),r=read();tp1=tp2=0;ans=1;
rep(i,1,n)
{
int x=read();
if(x>=l&&x<=r)s1[++tp1]=x;
else s2[++tp2]=x;
}
sort(s1+1,s1+tp1+1),sort(s2+1,s2+tp2+1);
s1[0]=l-1,s1[tp1+1]=r+1;int tmp=1,zero=0,L=1,R=ceil((D)(m+tp1)/(D)(r-l+1));
rep(i,0,tp1)if(s1[i+1]!=s1[i])zero+=s1[i+1]-s1[i]-1;
if(zero<m)
{
ans=-1;int ans2=-1,ans3=-1;
while(L<=R)
{
int mid=(L+R)>>1;int tmp=zero*mid,cnt=0,cnt2=0,cnt3=0;num=0;
rep(i,1,tp1)
{
num++;
if(s1[i]!=s1[i+1]){if(num<mid)tmp+=mid-num,cnt2++,cnt3+=num;num=0;}
}
if(tmp>=m){if(mid<ans||ans==-1)ans3=cnt3,ans=mid,ans2=cnt2;R=mid-1;}
else L=mid+1;
}
int num1=ans*(ans2+zero)-(m+ans3);tmp=ans;
ans=(LL)mul(ny[ans],ans2+zero-num1)*mul(ny[ans-1],num1)%mod;
}
num=0;
rep(i,1,tp1){num++;if(s1[i]!=s1[i+1]){if(num>=tmp)ans=(LL)ans*ny[num]%mod;num=0;}}
num=0;
rep(i,1,tp2){num++;if(i==tp2||s2[i]!=s2[i+1])ans=(LL)ans*ny[num]%mod,num=0;} ;
write((LL)ans*fac[n+m]%mod);
}
return 0;
}

并不对劲的bzoj5322:loj2543:p4561:[JXOI2018]排序问题的更多相关文章

  1. 洛谷P4561 [JXOI2018]排序问题(二分 期望)

    题意 题目链接 Sol 首先一种方案的期望等于它一次排好的概率的倒数. 一次排好的概率是个数数题,他等于一次排好的方案除以总方案,也就是\(\frac{\prod cnt_{a_i}!}{(n+m)! ...

  2. 【BZOJ5322】[JXOI2018]排序问题(模拟)

    [BZOJ5322][JXOI2018]排序问题(模拟) 题面 BZOJ 洛谷 题解 这题就显得很呆. 显然就是每次找到\([l,r]\)中出现次数最小的那个数并且放一个. 然后随便模拟一下就好了Qw ...

  3. 5322: [Jxoi2018]排序问题

    5322: [Jxoi2018]排序问题 链接 分析: 每次选一个出现次数最小的. 代码: #include<cstdio> #include<algorithm> #incl ...

  4. BZOJ5322 JXOI2018排序问题

    对于一个序列,重排后有序的概率显然是∏cnti!/n!,其中cnti为第i种数出现次数.要使概率最小,显然应该让各种数字尽量平均分配.剩下的是div2BC左右的大讨论. #include<ios ...

  5. BZOJ5322:[JXOI2018]排序问题——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5322 https://loj.ac/problem/2543 <-可以看数据,要没有这数据我 ...

  6. BZOJ5322 [Jxoi2018]排序问题 【贪心】

    题目链接 BZOJ5322 题解 意思就是使有序的排列尽量少 就是使相同的数尽量少 然后大力贪心即可 #include<algorithm> #include<iostream> ...

  7. BZOJ5322: [JXOI2018]排序问题

    传送门 不难看出期望就是 \(\frac{(n+m)!}{\prod_{v=1}^{max}(cnt_v!)}\),\(cnt_v\) 表示 \(v\) 这个数出现的次数. 贪心就是直接把 \(m\) ...

  8. [JXOI2018]排序问题

    嘟嘟嘟 这是今天做的第二道九条可怜的题,现在对他的题的印象是:表面清真可做,实则毒瘤坑人. 首先要感谢吉司机,我期望学的特烂,好在样例直接告诉我们期望怎么求了. 令\(b_i\)表示第\(i\)个不同 ...

  9. yyb省选前的一些计划

    突然意识到有一些题目的计划,才可以减少大量查水表或者找题目的时间. 所以我决定这样子处理. 按照这个链接慢慢做. 当然不可能只做省选题了. 需要适时候夹杂一些其他的题目. 比如\(agc/arc/cf ...

随机推荐

  1. FreeBSD 8

    FreeBSD 8.0的安装过程和7.2区别不大.先在FreeBSD官方网站上下载安装镜像,我一般都下载DVD的ISO,也有人爱好下最小的安装包,然后通过FTP或HTTP方式从网上下载各个程序包. 这 ...

  2. mySql 主从复制linux配置

    总结: 主库(192.168.1.251): /etc/my.cnf.d/server.cnf [mysqld] log-bin=mysql-bin server-id=1 从库(192.168.1. ...

  3. PS 基础知识 CMYK全称是什么

    已解决 请问谁知道CMYK四色的英文全称? 悬赏分:20 - 解决时间:2006-9-6 16:23 C代表什么颜色?英文全称是什么? M代表什么颜色?英文全称是什么? Y代表什么颜色?英文全称是什么 ...

  4. Linux C高级编程——网络编程基础(1)

    Linux高级编程--BSD socket的网络编程 宗旨:技术的学习是有限的,分享的精神是无限的. 一网络通信基础 TCP/IP协议簇基础:之所以称TCP/IP是一个协议簇,是由于TCP/IP包括T ...

  5. python(11)- 文件处理

    文件操作 1.1 对文件操作流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 现有文件如下: 昨夜寒蛩不住鸣. 惊回千里梦,已三更. 起来独自绕阶行. 人悄悄,帘外月胧明 ...

  6. [LeetCode]Insert Interval 考虑多种情况

    写太复杂了. 思想:确定带插入区间的每一个边界位于给定区间中的哪个位置,共同拥有5种情况 -1 |(0)_1_(2)|  (3) 当中.0,1,2这三种情况是一样的. 确定每一个带插入区间的两个边界分 ...

  7. 第14章8节《MonkeyRunner源代码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树

    在上几节的描写叙述中,我们把HierarchyViewer初始化好.也把ViewServer给装备好了.那如今距离获得一个控件去操作它是万事具备仅仅欠东风了,欠了那一股春风了?欠了的是建立控件树这个东 ...

  8. iOS移动开发周报-第16期

    iOS移动开发周报-第16期 [摘要]:本期iOS移动开发周报带来如下内容:i​OS 8的新特性,敏感逻辑的保护方案,iOS绘图教程,WKWebView的使用等. 教程 <i​OS 8>: ...

  9. nginx+thinkphp pathinfo模式配置

    server { listen 81; server_name http://lanxing.cc gohosts.com; root "D:\WWW\lanxing\public" ...

  10. sql无限级树型查询

    表结构如下: 表数据如下: 一提到无限级,很容易想到递归,使用sql 的CET语法如下 with menu(Id,Name,ParentId,Level) as ( select Id,Name,Pa ...