「DTOI-5」进行一个排的重 (Min Ver.) 题解
本题需要使用分类讨论。
这道题我们需要分
-
当重排前存在
i 满足p_i=q_i=n :重排后要使得答案最小,则必须把满足
a_i=(p_i,q_i)=(n,n) 的元素放在排列的第一项,让后面的数都没有贡献,所以第一问的答案是2 ;把
(n,n) 固定在开头后,后面n-1 个元素可以任意排列,第二问的方案数共有(n-1)! 种。 -
当重排前不存在
i 满足p_i=q_i=n :重排后要使得答案最小,则必须把
p_i=n 的一项或q_j=n 的一项放在排列的第一项;不妨设把
p_i=n 放在第一项,q_j 必然会比它前头的数大,只有排列第一项产生2 的贡献和q_j 产生的至少为1 的贡献,第一问答案是3 ;如果我们把
p_i=n 放在第一项,那么考虑q_j 怎么放才能产生正好为1 的贡献:只要不把大于q_i 的数放在q_j 的前面即可(因为如果我们这么做,那么会再产生若干贡献),方案数即为\dfrac{(n-1)!}{n-q_i} 。对称地,考虑把q_j=n 放在第一项的情况,总方案数即为\dfrac{(n-1)!}{n-q_i}+\dfrac{(n-1)!}{n-p_j} 。
除法可以用乘法逆元实现。
放代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
const int mod=998244353;
int f(int n){
int s=1;
for(int i=2;i<=n;i++)
(s*=i)%=mod;
return s;
}
int qpow(int a,int b){
int r=1;
while(b){
if(b&1)r=r%mod*a%mod;
a=a%mod*a%mod; b>>=1;
}
return r;
}
int inv(int x){return qpow(x,mod-2);}
// 快速幂求逆元
main(){
ios::sync_with_stdio(false);
int n,x,y; cin>>n;
vector<pii> a(n);
for(auto &i:a)cin>>i.first;
for(auto &i:a)cin>>i.second;
for(auto [p,q]:a){
if(p==n)x=q; if(q==n)y=p;
} // 找到 q[i] 和 p[j]
if(x==n)cout<<"2 "<<f(n-1)<<endl; // 第一种情况
else cout<<"3 "<<f(n-1)*((inv(n-x)+inv(n-y))%mod)%mod<<endl; // 第二种情况
return 0;
}