Wraith_Fiee的博客

CF1569C Jury Meeting

原题传送门

题目大意:nn个人召开会议,第ii个成员有aia_i项提议。先决定他们的顺序。然后按照顺序发言,如果当前人有提议,提出。否则,跳过。按顺序重复这个过程,第nn个人完成后再回到第11个人。如果没有人连续提出提议,则这个顺序是好的.求所有好的顺序的数量。答案模 998244353。

思路:分三种情况讨论。我们计最大值为mxmx,个数为tottot,次大值为mxmx',个数为cntcnt

第一种情况:mxmx>1mx-mx'>1时,不管怎么排列,最终mxmx都会剩余至少两次,就会连续提议,不符合条件,结果为00

第二种情况:tot>1tot>1时,不管如何排列都是符合条件的,结果为nn!

第三种情况:mx=mx+1mx=mx'+1并且tot=1tot=1时,对于这种情况来说,我们发现,只要在mxmx后面有一个mxmx'时,就是符合条件的序列。那我们只需要考虑mxmxmxmx'的次序,显然我们发现对于这cnt+1cnt+1个数,只有mxmx这个数排在最后这种情况不符合,那么符合条件的概率期望为cntcnt+1\frac{cnt}{cnt+1},那么对这nn个数的全排列来说,符合条件的排列为:n!cntcnt+1n!\frac{cnt}{cnt+1}

PS:习惯预处理阶乘,然后直接除以cnt+1cnt+1就会出错,因为预处理的阶乘是模modmod意义下的,这就导致直接除出问题了,所以除以cnt+1cnt+1要转变为乘以模modmod意义下的逆元

Code:

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10,mod=998244353;
typedef long long ll;
ll t,n,a[N],fac[N];
ll power(ll a,ll b){
    ll res=1;
    for(;b;b>>=1){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
    }
    return res;
}
int main(){
    cin>>t;
    while(t--){
        cin>>n;
        ll maxn=0;
        fac[0]=1;
        for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
        for(int i=1;i<=n;i++) {
            cin>>a[i];
            maxn=max(maxn,a[i]);
        }
        ll cnt=0,tot=0;
        for(int i=1;i<=n;i++){
            if(a[i]==maxn) tot++;
            if(a[i]==maxn-1) cnt++;
        }
        if(tot>1)  cout<<fac[n]<<endl;
        else if(tot==1&&cnt!=0) cout<<fac[n]*cnt%mod*power(cnt+1,mod-2)%mod<<endl;
        else cout<<"0"<<endl;
    }
    return 0;
}
在吹不出褶皱的日子里发光
Powered by Gridea