题解:P12558 [UOI 2024] Heroes and Monsters
masterhuang · · 题解
给定
n 个数a_1, a_2, \ldots, a_n, b_1, b_2, \ldots, b_n ,保证所有数均两两不同。定义
ans_k 表示满足如下条件的S\subseteq\{1,2,\cdots,n\},|S|=k 的集合S 个数:存在
1\sim n 的排列p ,满足:\begin{cases}a_i>b_{p_i}&(i\in S)\\[2pt]a_i<b_{p_i}& (i\not\in S)\end{cases} 求
ans_1,ans_2,\cdots,ans_n ,对998244353 取模。
首先将
依然先考虑判定性问题,如何判定
我们当然是直接贪心匹配,比如:最小的
记
-
a_{S_i} > b_i -
a_{T_i} < b_{|S|+i}
此时我们可以枚举
考虑优化,你发现每次 dp 的形式很类似,你每次重新做一遍很唐。
我们按照
我们发现
于是你只要考虑前缀是否放进
我们只需要对前后缀分别做一个背包然后卷起来即可,这东西和
比如后缀记
-
g_{i,j+1}\gets g_{i+1,j} -
g_{i,j}\gets g_{i+1,j}(a_i<b_{i+j})
时间复杂度
//洛谷 P12558
//https://www.luogu.com.cn/problem/P12558
#include<bits/stdc++.h>
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=5005,mod=998244353;
int n,m,a[N],b[N],f[N][N],g[N][N],s[N];
inline void ad(int &x,int y){x+=y;(x>=mod)&&(x-=mod);}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;
for(auto A:{a,b})
{
for(int i=1;i<=n;i++) cin>>A[i];
sort(A+1,A+1+n);
}f[0][0]=g[n+1][0]=1;
for(int i=1;i<=n;i++) for(int j=0;j<=i;j++)
f[i][j]=f[i-1][j],(j&&a[i]>b[j])&&(ad(f[i][j],f[i-1][j-1]),1);
for(int i=n;i;i--) for(int j=0;j<=n-i;j++)
g[i][j+1]=g[i+1][j],(a[i]<b[i+j])&&(ad(g[i][j],g[i+1][j]),1);
for(int i=0,j=0;i<=n;i++)
{
while(j<n&&a[j+1]<b[i]) j++;
for(int k=0;k<=i;k++) s[i]=(s[i]+1ll*f[j][k]*g[j+1][i-k])%mod;
}
for(int i=1;i<=n;i++) ad(s[i],s[i-1]);cin>>m;
for(int l,r;m--;)
{
cin>>l>>r;int S=s[r];
l&&(ad(S,mod-s[l-1]),1);cout<<S<<"\n";
}
return 0;
}