CF1768E Partial Sorting - 组合数学 -

题目链接:https://codeforces.com/contest/1768/problem/E

题解:
记 P1 为将 \(1..2\times n\) 排序, P2 为将 \(n+1..3\times n\) 排序
首先观察到答案一定不会超过 3( P1P2 之后 \(1..n\) 的所有数一定在 \(1..2n\) 中,这样只需要 P1 就可以排好,同理 \(n+1..2n\) & \(2n+1..3n\)

  • 答案为0的情况:\(1,2 .. 3n\) 一共一种
  • 答案为1:\(2n+1..3n\) 已经有序,\(1..2n\) 只需要一次 P1 即可,同理也有只需要一次 P2 的情况。注意减去重复情况( \(1..n\) & \(2n+1..3n\) 均有序,只需要一次 P1/P2,但是计算了 2 次,还有一个已经有序的情况),这里的答案是 \((2n)! - n! - 1\)

答案为 3 的情况不好统计,考虑先算出答案为 2 的情况,然后用 \((3n)!\) 减一下

  • 答案为 2 :显然对应的操作就是 P1P2 或者 P2P1 ,分别考虑这些对应的是什么情况:
    • P1P2:那么需要满足的条件是:\([1,2n]\) 中含有 \(1..n\) ,而且至少含一个 \(2n+1..3n\) 中的数,或者 \([1,2n]\)\(1..2n\) 的一个乱序排列,而且 \([2n+1,3n]\)\(2n+1..3n\) 的一个乱序排列(要注意这里面不能存在一次就能排好序的情况,因此很多“乱序”条件是应该的)。对应的答案:$$(\binom{2n}{n} \times n!-1)\times (\binom{2n}{n}\times n! - n!) \times n! + (n!-1)\times ((2n)!-n!)$$ 解释一下,第一个括号是选出 1~n 的位置并排列好,-1 是因为不能出现的情况是 1~n 在下标也是 1~n 的情况恰好有序了(这样只需要一次 P2 就行了); 第二个括号是利用容斥算出至少含 1 个 \(2n+1..3n\) 的数的情况并排列好,最后的 \(n!\) 是将 \([2n+1,3n]\) 的数排列好。加号后面的表示的是 [或者] 后面之后的情况。因为是乱序所以需要 -1,然后 \([1,2n]\) 随便排
    • P2P1:考虑如何去掉 P1P2 已经数过的情况,最后得出此处的要求是:\([n+1,3n]\) 中含有 \(2n+1..3n\) 所有的数,而且 \([2n+1,3n]\) 至少有 1 个 \(1..n\) 的数在 \([2n+1,3n]\) 中(这里就和 P1P2 不存在交集了),答案是:$$\sum_{k=1}^n \binom{n}{k} \times \binom{n}{n-k} \times ((2n)!-\binom{n}{k}\times k! \times (2n-k)!)$$。解释也很显然:先取 \(1..n\) 中的 \(k\) 个数,再挑 \(n+1..2n\) 中的 \(n-k\) 个,现在有了 \(2n\) 个数要填到 \([n+1,3n]\) 利用容斥就可以求出至少有一个 \(1..n\) 位于 \([2n+1,3n]\) 的方案数(钦定 \(k\) 个数都在 \([n+1,2n]\) 中,然后排列一下就行了)
  • 3 的情况就是 \((3n)!\) 减去上面的

代码:

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 3e6+5;

int n,mod=998244353;

int fac[maxn],inv[maxn];
int pw(int x,int y){
	if(!y)return 1;
	if(y==1)return x;
	int mid=pw(x,y>>1);
	if(y&1)return 1ll*mid*mid%mod*x%mod;
	return 1ll*mid*mid%mod;
}

int C(int x,int y){
	return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}

signed main(){
	scanf("%d%d",&n,&mod);
	fac[0] = inv[0] = 1;
	for(int i=1;i<=maxn-5;i++)fac[i] = 1ll*fac[i-1]*i%mod;
	inv[maxn-5]=pw(fac[maxn-5],mod-2);
	for(int i=maxn-6;i>=1;i--)inv[i] = 1ll*inv[i+1]*(i+1)%mod;
	
	ll t1 = (2ll*fac[2*n]%mod - fac[n]%mod - 1 + mod)%mod;
	ll t2 = (1ll*fac[n]*C(2*n,n)-1)%mod*(1ll*(C(2*n,n)-1)*fac[n]%mod)%mod*fac[n]%mod;
	(t2 += 1ll*(fac[n]-1)*(fac[2*n]-fac[n]+mod)%mod) %= mod;
	
	for(int k=1;k<=n;k++){
		ll tmp = 1ll*C(n,k)*C(n,n-k)%mod;
		tmp = tmp*(fac[2*n]-1ll*C(n,k)*fac[k]%mod*fac[2*n-k]%mod+mod)%mod*fac[n]%mod;
		(t2 += tmp) %= mod;
	}
	ll t3 = (fac[3 * n] - 1 - t1 + mod - t2 + mod) % mod;
	ll ans = (t1 + 2ll*t2%mod + 3ll*t3%mod) % mod;
	cout<<ans;
	
	return 0;
}
posted @ 2023-01-09 22:33  SkyRainWind  阅读(22)  评论(0编辑  收藏  举报