题解:P12761 [POI 2018 R2] 列车员 Conductor
DP 好题。
我们考虑先用 DP 求解第一个问题,定义
显然如果存在一个
我们发现以上式子是
容易发现转移可以变成一个区间取最小值,单点修改的问题,考虑直接上线段树维护。
要在这个基础上加上方案数也只需要考虑最小值状态的合并即可。
最后取答案时,我们记录下最大的
下附代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#define int long long
#define PII pair<int,int>
using namespace std;
const int mod=1000000007;
int t,m,n,q[1000005],a[1000005],mx[1000005],tot,pm[1000005];
PII l[500005],dp[1000005];
PII tr[4000005];
void pushup(PII &x,PII y,PII z){
if(y.first<z.first) x=y;
else if(z.first<y.first) x=z;
else x={y.first,y.second+z.second};
x.second%=mod;
}
void build(int k,int l,int r){
tr[k]={1e9,1};
if(l==r) return;
int mid=(l+r)/2;
build(k*2,l,mid),build(k*2+1,mid+1,r);
}
void update(int k,int l,int r,int x,int v1,int v2){
if(r<x||l>x) return;
if(l==r){
tr[k]={v1,v2};
return;
}
int mid=(l+r)/2;
update(k*2,l,mid,x,v1,v2);update(k*2+1,mid+1,r,x,v1,v2);
pushup(tr[k],tr[k*2],tr[k*2+1]);
}
PII query(int k,int l,int r,int x,int y){
if(r<x||l>y) return{1e9,1};
if(x<=l&&r<=y){
return tr[k];
}
int mid=(l+r)/2;
PII res;pushup(res,query(k*2,l,mid,x,y),query(k*2+1,mid+1,r,x,y));
return res;
}
bool cmp(PII x,PII y){
return x.second<y.second;
}
unordered_map<int,int>mp;
signed main(){
cin>>t;
while(t--){
cin>>m>>n;tot=0;mp.clear();
int mmx=0;
for(int i=1;i<=n;i++){
cin>>l[i].first>>l[i].second;
mmx=max(mmx,l[i].first);
q[++tot]=l[i].first,q[++tot]=l[i].second;
}
sort(l+1,l+n+1,cmp);
sort(q+1,q+tot+1);int cur=0;
for(int i=1;i<=tot;i++){
if(q[i]!=q[i-1]){
mp[q[i]]=++cur;pm[cur]=q[i];
a[cur-1]=q[i]-q[i-1];
}
}
a[cur]=m-q[tot];
int mxx=0;
build(1,1,cur);
for(int i=0;i<=cur;i++) mx[i]=0,dp[i]={0,0};
for(int i=1;i<=n;i++){
mxx=max(mxx,mp[l[i].first]);
mx[mp[l[i].second]]=mxx;
}
int res=0;
for(int i=1;i<=cur;i++){
if(mx[i]) res=mx[i];
mx[i]=res;
}
for(int i=1;i<cur;i++){
int lst=mx[i];
if(lst==0) dp[i]={1,a[i]};
else dp[i]=query(1,1,cur,lst,i-1),dp[i].first++,dp[i].second*=a[i];
dp[i].second%=mod;
update(1,1,cur,i,dp[i].first,dp[i].second);
}
PII ans={1e9,1};
for(int i=mp[mmx];i<cur;i++){
pushup(ans,ans,dp[i]);
}
cout<<ans.first<<' '<<ans.second%mod<<endl;
}
return 0;
}