【解题报告】Jury Meeting (9.8CF div2)

知识点总结

  • 排列组合
  • 思维
  • 乘法取模

题面

题目链接:Jury Meeting (9.8CF div2)
在这里插入图片描述
在这里插入图片描述

C. Jury Meeting


n people gathered to hold a jury meeting of the upcoming competition, the i-th member of the jury came up with ai tasks, which they want to share with each other.

First, the jury decides on the order which they will follow while describing the tasks. Let that be a permutation p of numbers from 1 to n (an array of size n where each integer from 1 to n occurs exactly once).

Then the discussion goes as follows:

If a jury member p1 has some tasks left to tell, then they tell one task to others. Otherwise, they are skipped.
If a jury member p2 has some tasks left to tell, then they tell one task to others. Otherwise, they are skipped.
...
If a jury member pn has some tasks left to tell, then they tell one task to others. Otherwise, they are skipped.
If there are still members with tasks left, then the process repeats from the start. Otherwise, the discussion ends.
A permutation p is nice if none of the jury members tell two or more of their own tasks in a row.

Count the number of nice permutations. The answer may be really large, so print it modulo 998244353.

Input
The first line contains a single integer t (1≤t≤104) — the number of test cases.

The first line of the test case contains a single integer n (2≤n≤2⋅105) — number of jury members.

The second line contains n integers a1,a2,…,an (1≤ai≤109) — the number of problems that the i-th member of the jury came up with.

The sum of n over all test cases does not exceed 2⋅105.

Output
For each test case, print one integer — the number of nice permutations, taken modulo 998244353.

Example
inputCopy
4
2
1 2
3
5 5 5
4
1 3 3 7
6
3 4 2 1 3 3
outputCopy
1
6
0
540

Note
Explanation of the first test case from the example:

There are two possible permutations, p=[1,2] and p=[2,1]. For p=[1,2], the process is the following:

the first jury member tells a task;
the second jury member tells a task;
the first jury member doesn't have any tasks left to tell, so they are skipped;
the second jury member tells a task.
So, the second jury member has told two tasks in a row (in succession), so the permutation is not nice.

For p=[2,1], the process is the following:

the second jury member tells a task;
the first jury member tells a task;
the second jury member tells a task.
So, this permutation is nice.

题目大意:

  • 在一次会议中有n个成员,每个成员有ai个事情需要讲述。现在需要给这n个人安排一个顺序讲述自己的事情,每次按照顺序每人只能讲一件事情。如果轮到一个人他的事情已经全部讲完了,那么就跳过到下一个人讲述,讲述的过程按照最初规定的顺序循环到每个人都把事情讲完为止。

  • 如果在安排的顺序中没有人连续讲述自己的事件2次以上我们就称为这个顺序为好顺序。

  • 给出人数n和每个人需要讲述的任务数量,求解好顺序的数量,对998244353取模。

思路

  • 首先我们需要找出任务数第一和第二多的人,记录下来(ma1,ma2)。
  • 如果(ma1-ma2)>1那么好序列的数量为0,易得。
  • 如果(ma1-ma2)=0那么好序列的数量为n的全排列。即A(n,n),易证。
  • 如果(ma1-ma2)=1
    • 首先找出序列中任务数量为ma1,ma2,其它数量,的人有几个,记录为num1,mum2,num3,但这里mum1一定为1,易证。
    • 我们首先需要把ma1和ma2结合在一起进行排列,但是ma1一定不能放在末尾,否则就会不满足要求。方案数为res=A(num2,num2)*num2
    • 在排好了ma1和ma2后,我们把其它任务数的人物依次插空,插空没有任何限制,设num=num1+num2
    • while(num3--) {res=res*(++num)}
    • res即为最后的答案。

正确代码

注意:小心取模运算不要遗漏!!!

//#pragma GCC optimize(2)
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<ctime>
#include<cstring>
#include<list>
#define int long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef  pair<int, int> PII;
const int N = 1e6 + 7,mod= 998244353;



int A(int m)
{
	int ans = 1;
	int k = m;
	while (k)
	{
		ans = (ans * (k )) % mod;
		k--;
	}
	return ans;
}

int t;
int n;
int a[N];

void solve()
{
	cin >> t;
	while (t--)
	{
		cin >> n;
		int ma1=-1, ma2=-1,num1=0,num2=0,num3=0;
		for (int i = 1; i <= n; i++)
		{
			cin >> a[i];
			if (a[i] > ma2)ma2 = a[i];
			if (ma2 > ma1)
			{
				int t = ma1;
				ma1 = ma2;
				ma2 = t;
			}
		}
		if (ma1 - ma2 > 1)
		{
			cout << 0 << endl;
			continue;
		}
		if (ma1 - ma2 == 0)
		{
			cout << A(n) << endl;
			continue;

		}
		if (ma1 - ma2 == 1)
		{
			int res = 1;
			for (int i = 1; i <= n; i++)
			{
				if (a[i] == ma1)num1++;
				else if (a[i] == ma2)num2++;
				else num3++;
			}
			res = 1 * (num2 ) * A(num2);
			res %= mod;
			int k = num1 + num2;
			while (num3--)
			{
				res *= k + 1;
				res %= mod;
				k++;
			}
			cout << res << endl;
		}
	}
}

signed main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	solve();
	return 0;
}

作者:Avalon Demerzel

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值