Educational Codeforces Round 113 (Rated for Div. 2) C. Jury Meeting(思维+数学)

C. Jury Meeting

题目

n个人发言,每个人都可以分一个次数,轮流发言,次数用尽就跳过,求有多少的分配排列可以使没有一个人连续发言。没有输出0.

思路

  • 先考虑怎样的次数序列总不合法,对于序列最大值 m a x max max,如果它很大显然会有人连续发言,现在找到这个“大的界限”。
  • 因为每一轮都会使发言次数减一,并且如果连续发言,此时一定只有一个次数非零的人,也就是说只要有一个人能充当“间隔” , 就不会使得人连续发言。
  • 因此考虑最大值 a a a和第二大值 b b b的关系。
    1. a = b a=b a=b时,显然在最后会是它们的交替,所有排列都合法。
    2. a − b > 1 a-b>1 ab>1时,总会出现连续,此时答案就为0
    3. a − b = 1 a-b=1 ab=1时,必须至少有一个b排在a的后面,详见下例。
/* 
2
1 2

1 2 ->  122 ->no
2 1 ->  212 ->yes
 */
  • 因此,现在只需要解决如何求最大值右边至少有一个次大值的排列数即可。
    设次大值有 t o t tot tot个,考虑这 t o t + 1 tot+1 tot+1个数,右边一个次大值都没的可能性是 1 1 + t o t \frac{1}{1+tot} 1+tot1,所求概率为 t o t 1 + t o t \frac{tot}{1+tot} 1+tottot.
    所以全排列乘上这个概率就行。

AC代码

时间复杂度: O ( n ) O(n) O(n)

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define debug(x) cout<<"> "<< x<<endl;
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 2e5 ,mod=998244353;
int n;
int a[N];
ll p[N];

ll ksm(ll _a,ll b)
{
    ll res = 1 ;
    while(b)
    {
        if(b&1) res=(res*_a)%mod;
        _a=(_a*_a)%mod;
        b>>=1;
        // debug(res)
    }
    return res%mod;
}

void solve()
{    
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+1+n);
    int tot = count(a+1,a+1+n,a[n]);
    if(tot>=2)
        cout<<p[n]<<endl;
    else 
    {
        tot = count(a+1,a+1+n,a[n]-1);
        if(tot==0)
            puts("0");
        else
        {
            // tot/(tot+1) * x;
            cout<<1ll*p[n]*tot%mod*ksm(tot+1,mod-2) %mod<<endl;
        }
    }
}
signed main()
{
    ios::sync_with_stdio();cin.tie();cout.tie();
    
    p[0]=1;
    for(int i=1;i<N;i++) p[i] = p[i-1]*i%mod;
    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

后记

取模古古怪怪,要专门看看安全取模的技巧。还有排列组合,也感觉懵逼的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值