P8321 『JROI-4』沈阳大街 2 题解

Inaba_Meguru

2022-05-08 17:00:44

Solution

一道蒟蒻做不出来的喵喵题 ## 题目简述 给定长度为 $n$ 的序列 $a,b$。$p$ 是 $1$ 到 $n$ 的排序,求: $$(\dfrac{1}{n!} \sum_p \prod_{i=1}^n \min (a_i,b_{p_i}))$$ ## 解题思路 我们把 $a,b$ 合并为一个新的数组 $c$。其中如果本来属于 $a$ 的染红,否则染蓝。对 $c$ 的数值从大到小排序,本题相当于这样的问题: > 在 $c$ 中不重复的配对 $n$ 对红蓝对,配对的权值是后面的数的权值,求所有配对权值的和。 考虑 $\text{dp}$ 解决。假设 $f[i][j]$ 表示 $c[1,i]$ 当中配对了 $j$ 个的方案数。 转移方程: $$f[i][j]=f[i-1][j-1]\times c[i]\times (tmp-(j-1))+f[i-1][j]$$ 这里 $tmp$ 是 $c[1,i-1]$ 中与 $c[i]$ 不同色的数的个数。 时间复杂度 $\mathcal O(n^2)$ 常数比较小,完结撒花。 ## 参考代码 ```cpp #include<iostream> #include<algorithm> using namespace std; #define ll long long const int MAXN=5e3+5; const int MOD=998244353; ll f[MAXN<<1][MAXN]; int cnt[2][MAXN*2]; struct element{ ll val,sub; }a[MAXN<<1];int n,A; bool cmp(element x,element y){ return x.val>y.val; } ll ksm(ll a,int b){ ll res=1; while(b){ if(b&1) res=res*a%MOD; a=a*a%MOD; b=b>>1; } return res; } int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>A,a[i]=element{A,0}; for(int i=1;i<=n;i++) cin>>A,a[i+n]=element{A,1}; sort(a+1,a+2*n+1,cmp); for(int i=1;i<=2*n;i++){ cnt[0][i]=cnt[0][i-1], cnt[1][i]=cnt[1][i-1]; cnt[a[i].sub][i]++; } f[0][0]=1; for(int i=1;i<=2*n;i++){ ll tmp=cnt[!a[i].sub][i]; f[i][0]=1; for(int j=1;j<=min(n,i);j++){ if(j<=tmp) f[i][j]=f[i-1][j-1]*a[i].val%MOD*(tmp-(j-1))%MOD; f[i][j]=(f[i-1][j]+f[i][j])%MOD; } } ll res=1; for(int i=1;i<=n;i++) res=res*i%MOD; cout<<ksm(res,MOD-2)*f[2*n][n]%MOD; return 0; } ```