zoukankan      html  css  js  c++  java
  • [CF-Edu113]C. Jury Meeting

    [CF-Edu113]C. Jury Meeting

    题目

    (n)个人,第(i)个人有(a_i)句话要说,你可以安排一个发言顺序(是一个(1sim n)的排列),如果有人有话说,就进行发言,轮到第(i)个人时,若TA有话说,就说一句,不然就跳过.一个发言顺序良好,当且仅当任何一个人不会连续发言,问良好的发言顺序的数量,取模.

    没想到in a row还可以翻译成连续

    思路

    题目说的这么绕,简化一下吧.

    (a)数组的最大值出现了(num1),次大值出现了(num2)次,若(num1 > 1),不管怎么排列都是合法的,方案数就是(n!).否则,又有两种情况:①最大值减次大值大于1,不管怎么都是不合法的,输出0;②最大值恰好比次大值大1,这也是需要我们详细讨论的.

    我们单独把(a)的最大值和次大值单独拿出来分析:

    一个顺序要是合法,最大值就不能放在最后面(注意这里"最后"的含义,已经忽略了最大值次大值以外的东西),显然,不合法的排列方案数就是(num2!)(最大值要放在最后面).

    最大值次大值以外的,是可以随便排的,方案数是((n-num1-num2)!).

    然后把两个排列合并起来,使原来在同一个排列的两个元素相对顺序不改变(我语文不好),的方案数就是(C_n^{num2+num1})(具体可以看这个:[ABC217]F - Make Pair).

    综上,这个情况的答案就是(num2!cdot (n-num1-num2)! cdot frac{n!}{(num2+num1)! (n-num2-num1)!}=num2!cdot frac{n!}{(num2+num1)!})

    代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    template <class T>
    T read() {
    	T re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' ,c = getchar();
    	return negt ? -re : re;
    }
    
    typedef long long LL;
    const LL mod = 998244353;
    const int N = 200010;
    
    int n;
    int a[N];
    LL fac[N] , inv[N];
    
    LL Pow(LL a , int p) {
    	LL res = 1;
    	while(p) {
    		if(p & 1)
    			res = res * a % mod;
    		a = a * a % mod;
    		p >>= 1;
    	}
    	return res;
    }
    int main() {
    	fac[0] = inv[0] = 1;
    	for(int i = 1 ; i < N ; i++)
    		fac[i] = fac[i - 1] * i % mod;
    	for(int i = 1 ; i < N ; i++)
    		inv[i] = Pow(fac[i] , mod - 2);
    
    	int T = read<int>();
    	while(T--) {
    		n = read<int>();
    		for(int i = 1 ; i <= n ; i++)
    			a[i] = read<int>();
    		int maxa = 0;
    		for(int i = 1 ; i <= n ; i++)
    			if(maxa < a[i])
    				maxa = a[i];
    
    		int num1 = 0 , num2 = 0;
    		for(int i = 1 ; i <= n ; i++)
    			if(a[i] == maxa)
    				++num1;
    			else if(a[i] == maxa - 1)
    				++num2;
    
    		if(num1 > 1) {
    			printf("%d
    " , fac[n]);
    		} else {
    			printf("%d
    " ,(
    			           fac[n] -
    			           fac[num2]
    			           * fac[n - num2 - 1] % mod
    			           * fac[n] % mod
    			           * inv[num2 + 1] % mod
    			           * inv[n - num2 - 1] % mod
    
    			           + mod) % mod
    			      );
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于android表单多字段布局的一些思考
    thrift 试用
    关于带角度的箭头
    同步和异步
    storm各组件基本概念
    AWK使用实例
    Hotspot虚拟机目录结构
    大数据生态
    代码生成器 架构提取工具tqdemo
    [源码]C# to SQL 的翻译器.net 1.1版
  • 原文地址:https://www.cnblogs.com/dream1024/p/15254255.html
Copyright © 2011-2022 走看看