题意简述
给定 条闭区间。对于每个 ,求大小为 、交图为树的区间集合数量。
解题思路
将区间按 升序排序。此前与 相交的区间都覆盖 。故交图为树等价于每条区间除第一条外恰与一条旧区间相交。设此前最大的两个右端点为 。不足两条时令 。合法条件即 。
选择 后,直接跳到 ,其中 ,并保留 。设 表示从后缀 中再选 条区间,保留右端点为 的方案数,则
边界为 ,枚举第一条区间即可统计答案。按 滚动数组,时间复杂度为 ,空间复杂度为 。
参考代码
#include "segment.h"
#include <bits/stdc++.h>
using namespace std;
const int N=3005;
const int M=1005;
const int mod=998244353;
pair<int,int> a[N];
int f[2][N][M],nxt[M],ans[N];
void init(int c,int t){}
vector<int> segment(int n,int m,int k,vector<int> l,vector<int> r)
{
for(int i=0;i<n;i++)a[i]={l[i],r[i]};
sort(a,a+n);
for(int x=0;x<=m;x++)nxt[x]=upper_bound(a,a+n,make_pair(x,m))-a;
for(int i=0;i<=n;i++)for(int x=1;x<=m;x++)f[0][i][x]=1;
ans[1]=n;
int t=1;
for(int s=2;s<=k;s++)
{
ans[s]=0;
memset(f[t][n],0,sizeof f[t][n]);
for(int i=n-1;i>=0;i--)
{
for(int x=1;x<=m;x++)
{
f[t][i][x]=f[t][i+1][x];
if(a[i].first<=x)f[t][i][x]+=f[t^1][nxt[min(x,a[i].second)]][max(x,a[i].second)];
f[t][i][x]%=mod;
}
}
for(int i=0;i<n;i++)ans[s]=(ans[s]+f[t][i+1][a[i].second])%mod;
t^=1;
}
return vector<int>(ans,ans+k+1);
}