「JXOI 2018」 排序問題
阿新 • • 發佈:2019-02-23
快速冪 while else 分布 個數 不同 () printf ble 盡量小
題目鏈接
戳我
\(Solution\)
\(50\ pts\)
我們來看一下題目,可以很容易的寫出來答案的式子:
\[\frac{(n+m)!}{a_1!a_2!...a_{tot}!}\]
\(a_1,a_2,...,a_{tot}\)為\(n+m\)個數中不同的數出現的個數
那麽\(50\)便很好想了.
我們現在要求的是期望輪數最多,所以\({a_1!a_2!...a_{tot}!}\)要盡量小
所以我們可以貪心求解,每次找出\([l,r]\)中出現次數最少的數,找\(m\)次即可,這用個堆維護一下就好了
\(100 \ pts\)
我們還是需要\({a_1!a_2!...a_{tot}!}\)
於是我們可以二分出\(a_1,a_2,...,a_{tot}\)中的最小值的最大值,我們令這個值為\(ans\)
那麽我們現在就可以知道了\(a_1,a_2,...,a_{tot}\)的分布
對於\(>ans\)的或不在[l,r]這個區間內的,直接將他們階乘乘起來即可.
對於[l,r]內個數\(<=ans\)的,進行如下操作:
算出將[l,r]內個數\(<=ans\)的邊成\(ans\)後剩下\(m\)個數還剩下幾個.我們令這個數為\(c\),[l,r]內去見個數\(<=ans\)的數有\(k\)個
我們將這\(c\)個數分成不同的\(c\)個插入數列即可.
所以現在的個數為:
\(c\) 個個數為 \(ans+1\)
\(k-c\)個個數為 \(ans\)
直接快速冪求,最後吧求的乘起來,用\((n+m)!\)除他就好了.
\(Code\)
#include<bits/stdc++.h> #define int long long #define rg register #define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout); using namespace std; const int mod=998244353; inline int read(){ int x=0,f=1;char c=getchar(); while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar(); while(c>='0'&&c<='9') x=x*10+c-48,c=getchar(); return f*x; } int n,m,tot,a[2000010],sum[2000010]; inline int check(int x,int len){ int ans=0,flag=0; for(int i=1;i<=tot;i++){ if(sum[i]>x) break; ans+=sum[i],flag=i; } int k=(len-tot+flag); return m-(k*x-ans); } inline int ksm(int a,int b){ int ans=1; while(b){ if(b&1) ans=ans*a%mod; a=a*a%mod,b>>=1; } return ans; } int jc[20000010]; main(){ int T=read(),l,r; jc[0]=1; for(int i=1;i<=10200000;i++) jc[i]=jc[i-1]*i%mod; while(T--){ n=read(),m=read(),l=read(),r=read(),tot=0; for(int i=1;i<=n;i++) a[i]=read(); sort(a+1,a+1+n); int p=0,js=1; a[n+1]=-2147483647; for(int i=1;i<=n+1;i++){ if(a[i]!=a[i+1]){ if(a[i]<=r&&a[i]>=l) sum[++tot]=i-p; else js=js*jc[(i-p)]%mod; p=i; } } sort(sum+1,sum+1+tot); int L=0,R=m+n,maxx=0; while(L<=R){ int mid=(L+R)>>1; if(check(mid,(r-l+1))>=0) L=mid+1,maxx=max(maxx,mid); else R=mid-1; } int ans=0,flag=0,len=(r-l+1); for(int i=1;i<=tot;i++) { if(sum[i]>maxx) break; ans+=sum[i],flag=i; } int k=(len-tot+flag),c=m-(k*maxx-ans); for(int i=flag+1;i<=tot;i++) js=js*jc[sum[i]]%mod; js=js*ksm(jc[maxx+1],c)%mod,js=js*ksm(jc[maxx],k-c)%mod; printf("%lld\n",jc[n+m]*ksm(js,mod-2)%mod); } return 0; }
「JXOI 2018」 排序問題