C. Jury Meeting
题意:
n
n
n 个数,代表每个人可以发言次数,要求每个人发言不能连续发言,例如
1
,
2
1,2
1,2,1发言,2发言,然后还是2发言,这个情况就不行。然后求排列个数,满足这个条件。
思路:
首先可以想到最大值如果不止
1
1
1 个,那么直接输出
n
n
n的全排列就完了
如果最大值和次大值差值大于
1
1
1,输出
0
0
0,无论如何都无法满足
最后剩下最大值仅有一个,次大值至少一个的情况
我们统计一下次大值的个数,然后一个条件是显然的:最大值右边至少有一个次大值,关键是如何求排列。我们考虑插空法,设有
c
n
t
cnt
cnt 个次大值,
c
n
t
+
1
cnt+1
cnt+1 个空可以插最大值,只有一个空是不满足条件的,就是把最大值插在最右边。然后答案就是
n
!
×
c
n
t
c
n
t
+
1
n! \times \frac{cnt}{cnt+1}
n!×cnt+1cnt
这个地方比较巧妙,计算比例
c
n
t
c
n
t
+
1
代
表
的
是
满
足
条
件
的
比
例
,
然
后
乘
以
所
有
的
排
列
\frac{cnt}{cnt+1} 代表的是满足条件的比例,然后乘以所有的排列
cnt+1cnt代表的是满足条件的比例,然后乘以所有的排列
太妙了,组合数学还是太菜了
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 9;
const ll mod = 998244353;
const ll inf = 0x3f3f3f3f;
ll n, m, k;
ll a[maxn];
ll Pow[maxn];
ll q_pow(ll a, ll n)
{
ll ans = 1;while(n){
if(n & 1) ans=(ans * a) % mod;a=(a*a)%mod;n>>=1;
}return ans;
}
bool cmp(ll a, ll b){
return a > b;
}
void work()
{
cin >> n;
int sum = 0;
for(int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + 1 + n, cmp);
if(a[1] == a[2]) cout << Pow[n] << endl;
else if(a[1] - a[2] > 1) cout << 0 << endl;
else
{
int cnt = 0;
for(int i = 1; i <= n; ++i) if(a[i] == a[2]) ++cnt;
cout << Pow[n] * cnt % mod * q_pow(cnt + 1, mod - 2) % mod << endl;
}
}
int main()
{
ios::sync_with_stdio(0);
Pow[0] = 1;
for(int i = 1; i <= maxn - 9; ++i) Pow[i] = Pow[i-1] * i % mod;
int TT;cin>>TT;while(TT--)
work();
return 0;
}

这篇博客探讨了一个有趣的算法问题,即给定一组数字,要求每个人发言次数不超过其数值且不能连续发言。博主分析了不同情况下满足条件的排列数量,特别关注了最大值唯一和次大值存在的情况。通过插空法和组合数学,博主巧妙地计算了满足条件的排列比例,并给出了高效的代码实现。

被折叠的 条评论
为什么被折叠?



