题目题意

一个 2n 的排列的卡牌在随机排序的情况下,被平均分为两份(即两个长度为n的数组),一份给小苯,一份给小红,他们拿着这两份卡牌来做游戏,两人拿出卡牌最前面的那个数字,数字大者赢,数字拿走并且积分加1,而输者的卡牌则保持不动,直至有一方的卡牌没有。

题目要求

帮助小苯拿到尽可能多的积分(注意无关输赢),并且计算出能得到最多分数的组合数。

题目知识点

组合数、数学、贪心思想

题目分析

既然我们要使小苯的积分尽可能的多,而且结合题意,只有赢者的那张卡牌才能被拿走,那么这时,我们就可以去攻击小红的软肋(小红手里最小的那张牌),通过小红的这个软肋,我们就可以最大化小苯拿走的牌的数量,即积分更可能的多,所以我们可以先去找小红手里最小的那张牌,即:

		int minn=400010; //题目给的最大排列数为4e5,我们只需要定义的稍大即可
		for(int i=1;i<=n;i++){
            cin>>b[i];
            minn=min(minn,b[i]); //找到小红最小牌
        } 

然后我们就可以根据这个minn(小红的最小牌),来计算出小苯通过攻击小红的这个软肋通过的最多牌数

		int x=0;
		for(int i=1;i<=n;i++){
            if(a[i]>minn) x++;
        }

当我们得到我们的最大牌数时,我们会发现,不管这些数如何排,我们都可以去战胜小红的软肋,而小苯剩余的牌不管怎么排,都可能打过小红,所以我们就可以根据这个x来计算其阶乘,以及(n-x)的阶乘

		long long ans=1;
		for(int i=1;i<=x;i++){
            ans=(ans*i)%mod; //计算x的阶乘
        }
        for(int i=1;i<=n-x;i++){
            ans=(ans*i)%mod; //计算n-x的阶乘,这里将n!和(n-x)!直接乘起来了
        }

最后我们就可以直接输出答案啦

完整代码如下:

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int a[200010];
int b[200010];
void solve(){
    int n;
    cin>>n;
  	int minn=400010;
    for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++){
            cin>>b[i];
            minn=min(minn,b[i]);
        } 
  		int x=0;
        for(int i=1;i<=n;i++){
            if(a[i]>minn) x++;
            else y++;
        }
  		long long ans=1;
        for(int i=1;i<=x;i++){
            ans=(ans*i)%mod;
        }
        for(int i=1;i<=n-x;i++){
            ans=(ans*i)%mod;
        }
        cout<<ans<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
}