Educational Codeforces Round 113 (Rated for Div. 2) C. Jury Meeting

传送门

题意:

给你一个序列,每次从头到尾每一次让不为0的值减1,执行数次直到序列中所有数为0,问你满足序列中不会出现同一个数连续减两次的排列的种数。

思路:

易得:当序列中至少有一个最大数在所有比它小1的数的右边,那么该序列不满足条件,为了方便,考虑反面,用整个序列全排列的个数减去反面的个数。
考虑反面:当一个最大数在第n位时,这种情况的个数为: A n − 1 n − 1 ∗ A 最 大 数 个 数 最 大 数 个 数 ∗ A 比 最 大 数 小 一 的 数 的 个 数 比 最 大 数 个 数 小 一 的 数 的 个 数 A_{n-1}^{n-1}*A_{最大数个数}^{最大数个数}*A_{比最大数小一的数的个数}^{比最大数个数小一的数的个数} An1n1AA
当一个最大数在第n-1位时,设a=n-比最大数小1的数的个数-最大数的个数的阶乘,这种情况的个数为: A a a ∗ A 最 大 数 个 数 最 大 数 个 数 ∗ A 比 最 大 数 小 一 的 数 的 个 数 比 最 大 数 个 数 小 一 的 数 的 个 数 A_a^a*A_{最大数个数}^{最大数个数}*A_{比最大数小一的数的个数}^{比最大数个数小一的数的个数} AaaAA
…以此类推。

#include<bits/stdc++.h>
#include<ctime>
using namespace std;
#define ll long long 
const int mod = 998244353;
ll a[200010];
ll sum[200010];
ll A[200010];
map<ll,ll>vis;
long long qpow(long long c, long long b)
{
    
    
	long long sum = 1;
	while (b) {
    
    
		if (b & 1) {
    
    
			sum = (sum * c) % mod;
			b--;
		}
		b /= 2;
		c = c * c % mod;
	}
	return sum%mod;
}
int main()
{
    
    
	int t;
	cin>>t;
	while(t--)
	{
    
    
		memset(sum,0,sizeof(sum));
		vis.clear();
		int n;
		cin>>n;
		ll maxx = 0;
		int flag = 1;
		for(int i = 1; i <= n; i++)
		{
    
    
			cin>>a[i];
			vis[a[i]]++;
			if(i > 1)
			{
    
    
				if(maxx == a[i] && flag)flag = 1;
				else flag = 0;
			}
			maxx = max(maxx, a[i]);
		}
		ll ans = 1;
		for(int i = 2; i <= n; i++)ans*=i, ans%=mod;
		if(flag)
		{
    
    
			cout<<ans%mod<<endl;
			continue;
		}
		if(vis[maxx] > 1)
		{
    
    
			cout<<ans%mod<<endl;
			continue;
		}
		ll res = 0;
		if(vis[maxx-1])
		{
    
    
			ll num = vis[maxx-1];
			ll maxx_sum = vis[maxx];
			A[0] = 1;
			for(int i = 1; i <= n; i++)A[i] = A[i-1]*i%mod;
			ll last = n-maxx_sum-num;
			sum[0] = 1;
			ll now = last;
			for(int i = 1; i <= last; i++)
			{
    
    
				sum[i] = sum[i-1]*now%mod;
				now--;
			}
			ll res = 0;
			for(int i = n; i >= num+vis[maxx]; i--)
			{
    
    
				res += sum[n-i]%mod*A[i-1]%mod*A[maxx_sum]%mod;
				res%=mod;
			}
			cout<<(ans+mod-res)%mod<<endl;
		}
		else cout<<0<<endl;
	}
}

おすすめ

転載: blog.csdn.net/p15008340649/article/details/120212712