链接:https://ac.nowcoder.com/acm/contest/120561/B 来源:牛客网
题目描述
小苯正在和小红玩卡牌游戏。游戏中有 2×n 张牌,每张牌上都有一个数字,所有牌的数字恰好构成了一个长度为 2×n 的排列。 游戏最初时, 2×n 张卡牌被恰好平均分成了两组 n 张牌,并分别发给了两人,小苯第 i 张牌上的数字是 𝑎 𝑖 ,而小红第 i 张牌上的数字是 𝑏 𝑖 ,具体的游戏过程如下:如果两人之中有一人已经没有牌了,则游戏结束。
比较两人当前手牌中的最前一张,对应数字大的那一方得一分并将该张牌从自己手牌移除;另一方不得分,手牌也不变。随后进入下一轮。
而现在小苯希望自己的得分尽可能多,为此他在游戏开始前可以任意地重新排列自己的牌,以得到更高的游戏分数。 现在你的任务则是求出,有多少种重新排列(选择不进行重排也是一种方案)的方式,能使得小苯得到他能得到的最高分。由于答案可能很大,请将答案对 998244353 取模后输出。
【名词解释】 长度为 𝑛 n 的排列:由 1,2,…,n 这 n 个整数、按任意顺序组成的数组(每个整数均恰好出现一次)。例如, {2,3,1,5,4} 是一个长度为 5 的排列,而 {1,2,2} 和 {1,3,4} 都不是排列,因为前者存在重复元素,后者包含了超出范围的数。
输入描述:
每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≦T≦10 ^ 5 ) 代表数据组数,每组测试数据描述如下:
第一行输入一个正整数
n(1≦n≦2×10 ^
5
),表示两人的卡牌数量。
第二行输入
n 个正整数
𝑎
1
,
𝑎
2
,
…
,
𝑎
𝑛
(
1
≦
𝑎
𝑖
≦
2
×
𝑛
),表示小苯的卡牌上的数字。
第三行输入
𝑛
n 个正整数
𝑏
1
,
𝑏
2
,
…
,
𝑏
𝑛
(
1
≦
𝑏
𝑖
≦
2
×
𝑛
),表示小红的卡牌上的数字。
(保证
a 数组和
b 数组共同构成一个长度为
2×n 的排列。)
除此之外,保证单个测试文件的 n 之和不超过 2×10 ^ 5 。
输出描述:
对于每一组测试数据,新起一行输出一个整数,表示小苯重新排列自己卡牌,使得他能得到的最高分的方案数对 998244353 取模后的值。
题解如下:
题目要求小苯需要获得最高分,这无疑是需要使数组a中的元素尽可能多的去除,因此,我们需要找到b数组中最小的数,由于b数组无法移动和改变,所以我们只需要计算a数组中大于b数组中mn值的数的个数,并计算此个数的全排列,再计算剩下数的个数的全排列,两者相乘取模即可,由于大于mn值的a数组中的元素放的靠前,所以在这些元素被移除之前,mn一直未被移除,所以可以保证得到最高分,而小于mn的元素无法得分,故两者分开全排列相乘取模即为答案。
代码附上:
#define endl '\n'
#define fs first
#define sc second
#define mod 998244353
#define N 10000000000
#define PI 3.141592653589793238462643383279L
using namespace std;
typedef long long int ll;
vector<ll>vt(201000);
ll A(ll a)
{
return vt[a];
}
void solve()
{
ll n,mn,cnt=0;
cin>>n;
mn=2*n+1;
vector<ll>vc(n);
for(ll i=0;i<n;i++)
cin>>vc[i];
for(ll i=0;i<n;i++)
{
ll num;
cin>>num;
mn=min(mn,num);
}
for(ll i=0;i<n;i++)
if(vc[i]>mn)cnt++;
if(cnt==0||cnt==n)cout<<A(n)<<endl;
else
cout<<(A(cnt)*A(n-cnt))%mod<<endl;
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
ll _=1;
vt[1]=1;
for(ll i=2;i<201000;i++)
vt[i]=(vt[i-1]%mod)*(i%mod)%mod;
cin>>_;
while(_--)
solve();
return 0;
}
如有错误烦请指正谢谢

京公网安备 11010502036488号