【题解】P5979 [PA 2014] Druzyny
P5979 [PA 2014] Druzyny
题意
有 \(n\) 个人排成一行(从 \(1\) 到 \(n\) 编号),把他们分成若干组,每一组都是编号连续的一段,每个人属于且仅属于一个组。
第 \(i\) 个人期望它所在的组的人数 \(\in [c_i,d_i]\),否则这个分组方案就是不合法的。
求可以分成的组的数目的最大值,以及有多少种分组方案能达到最大值。
题解
知识点:动态规划,扫描线,线段树,cdq 分治。
远古疑难杂症,年初的时候写了发暴力就跑路了,今天来解决它。
设 \(f_i\) 表示考虑了前 \(i\) 个,最多能分多少组。
设 \(g_i\) 表示考虑了前 \(i\) 个,在最优分组数的前提下的有多少种方案。
假设 \(j-1\) 能转移到 \(i\)(即将 \(j\sim i\) 分为一组),则应该满足以下条件:
\[\max_{k=j}^i c_k \le i-j+1 \le \max_{k=j}^i d_k
\]
非常棘手的条件,每一项都有 \(i,j\),直接做根本优化不了,我们想要的的条件应该是每一项只有 \(i\) 或者 \(j\)。
这时候就可以考虑 cdq 分治了,设当前局面为区间 \([l,r]\),设定一个 \(mid\),使 \(j\in [l,mid]\),\(i\in [mid+1,r]\)。
则上面的条件可以拆为两个:
\[\max_{k=j}^{mid} c_k \le i-j+1 \le \max_{k=j}^{mid} d_k
\]
\[\max_{k=mid+1}^i c_k \le i-j+1 \le \max_{k=mid+1}^i d_k
\]
然后进行移项得到:
\[\max_{k=j}^{mid} c_k +j-1 \le i \le \max_{k=j}^{mid} d_k +j-1
\]
\[-\max_{k=mid+1}^i d_k+i+1\le j \le -\max_{k=mid+1}^i c_k +i+1
\]
可以发现这两个条件都是每一项只有 \(i\) 或者 \(j\),这意味着我们可以分开处理。
对于 \(j\),通过处理第一个条件可以划定满足条件的 \(i\),计算出区间,用扫描线简单维护。
对于 \(i\),通过处理第二个条件可以选定满足条件的 \(j\),直接计算出区间,去扫描线维护的线段树上询问即可。
时间复杂度 \(O(n \log^2 n)\)。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 1002506
#define int long long
const int mod=1e9+7;
int n,c[N],d[N];
pr dp[N];
vector<int>ad[N],dl[N];
inline pr mg(pr x,pr y){
if(x.fi==y.fi){
return {x.fi,(x.se+y.se)%mod};
}
if(x.fi>y.fi){
return x;
}
return y;
}
struct segt{
#define mid ((l+r)>>1)
pr tr[N<<2];
inline void build(int k,int l,int r){
tr[k]={-1e18,0};
if(l==r){
return;
}
build(k*2,l,mid);
build(k*2+1,mid+1,r);
}
inline void upd(int L,int k,int l,int r,pr d){
if(l==r){
tr[k]=d;
return;
}
if(L<=mid){
upd(L,k*2,l,mid,d);
}
else{
upd(L,k*2+1,mid+1,r,d);
}
tr[k]=mg(tr[k*2],tr[k*2+1]);
}
inline pr ask(int L,int R,int k,int l,int r){
if(L<=l&&R>=r){
return tr[k];
}
pr ans={-1e18,0};
if(L<=mid){
ans=mg(ans,ask(L,R,k*2,l,mid));
}
if(R>mid){
ans=mg(ans,ask(L,R,k*2+1,mid+1,r));
}
return ans;
}
#undef mid
}t;
inline void cdq(int l,int r){
if(l==r){
if(c[l]>1){
return;
}
pr pre=dp[l-1];
pre.fi++;
dp[l]=mg(dp[l],pre);
return;
}
int mid=(l+r)>>1;
cdq(l,mid);
int C=0,D=1e9;
per(i,l,mid){
C=max(c[i],C);
D=min(d[i],D);
int L=max(mid+1,C+i-1),R=min(r,D+i-1);
if(L<=R){
ad[L].pb(i);
dl[R+1].pb(i);
}
}
C=0,D=1e9;
rep(i,mid+1,r+1){
for(int x:ad[i]){
t.upd(x,1,0,n,dp[x-1]);
}
for(int x:dl[i]){
t.upd(x,1,0,n,{(int)-1e18,0});
}
C=max(c[i],C);
D=min(d[i],D);
int L=max(l,i+1-D),R=min(mid,i+1-C);
if(L<=R){
pr res=t.ask(L,R,1,0,n);
res.fi++;
dp[i]=mg(dp[i],res);
}
ad[i].clear();
dl[i].clear();
}
cdq(mid+1,r);
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
dp[0]={0,1};
t.build(1,0,n);
rep(i,1,n){
dp[i]={-1e18,0};
cin>>c[i]>>d[i];
}
cdq(1,n);
// rep(i,1,n){
// cout<<dp[i].fi<<' '<<dp[i].se<<"\n";
// }
if(!dp[n].se){
cout<<"NIE";
}
else{
cout<<dp[n].fi<<' '<<dp[n].se;
}
return 0;
}

浙公网安备 33010602011771号