牛客小白月赛117 F.中位数
F.中位数
题意简述
\(\hspace{15pt}\)给定一个整数 \(n\),现在对于一个长度为 \(n\) 的排列 \(p_1,p_2,\dots,p_n\),其价值 \(\operatorname{v}(p)\) 定义为:
\(\operatorname{v}(p)=\textstyle\prod\limits_{l=1}^{n}\textstyle\prod\limits_{r=l}^{n}\operatorname{mid}(l,r)\)
\(\hspace{15pt}\)现在,需要你求出所有 \(n!\) 种不同排列的价值的总乘积。由于答案可能很大,请将答案对 \(1\,610\,612\,741\)(TXT文本复制:1610612741)取模后输出。
【名词解释】
\(\hspace{15pt}\)\(\operatorname{mid}(l,r)\) 指的是区间 \([l,r]\) 内第 \(\left \lceil \tfrac{r-l+1}{2} \right \rceil\) 大的数值,例如:数组 \(\{1,2,3,4\}\) 中第 \(1\) 大是 \(4\),第 \(2\) 大是 \(3\),第 \(3\) 大是 \(2\),第四大是 \(1\),所以,这个数组的中位数是第 \(2\) 大的数,是 \(3\)。
解题思路
贡献法分析,考虑每个数 \(a_i\) 成为中位数的可能种类数 \(p_i\) 最后的答案就是 \(ans=i_1^{p_1}·i_2^{p_2}·i_3^{p_3}...i_n^{p_n}\),现单独考虑每个数成为中位数的种类数 \(p_i\)如何计算, 当一个数成为中位数时可以枚举区间长度,如果当前区间长度为 \(len\) .则左边肯定有 \([len/2]\)个元素 ,而右边有 \([\frac{len}{2} - (len\%2==0)]\) 个元素,在考虑区间内部所有数全排列和区间外数全排列,再乘上区间内外相对顺序,最后得到公式 \(p_i= C_{i-1}^{\frac{len}{2}}·C_{n-i}^{[\frac{len}{2} - (len\%2==0)]}·len!·(n-len+1)!\) 。注意由于欧拉降幂,幂次里面的数模数是\(\mod-1\),外面才是 \(mod\) .
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll mod=1610612741;
const ll MOD=mod-1;//欧拉降幂
ll q_pow(ll a,ll b,ll m=mod){
ll s=1;
while(b){
if(b&1){
s=s*a%m;
}
a=a*a%m;
b>>=1;
}
return s;
}
struct Comb{
vector<vector<ll> >C;
vector<ll>fac;
Comb(int n){
init(n);
}
void init(int n){
C.resize(n+1);
fac.resize(n+1);
for(int i=0;i<=n;i++) C[i].resize(n+1);
for(int i=0;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++){
C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
}
}
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
}
}comb(6e3+5);//组合数板子
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n;cin>>n;
ll ans=1LL;
for(int i=1;i<=n;i++){ //枚举谁是中位数
ll tot=0;
for(int len=1;len<=n;len++){//中位数区间的长度
ll c=comb.C[i-1][len/2]*comb.C[n-i][len/2-(len%2==0)]%MOD;
ll t=comb.fac[len]*comb.fac[n-len+1]%MOD;
tot=(tot+c*t%MOD)%MOD;
}
ans=ans*q_pow(i,tot%MOD)%mod;
}
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号