题解:P12761 [POI 2018 R2] 列车员 Conductor
一道双指针优化 DP 题。
题意
给定一个长为
状态
先离散化。定义
转移
显然,
我们定义
这里就用双指针优化。我们发现,由于考虑的区间只会增加,
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+5;
long long T,n,m,p=1e9+7,l,r,k[maxn],cnt,xx[maxn],yy[maxn],d[maxn][2],s[maxn][2],ss[maxn];
struct xxx
{
int x,y,z;
bool operator < (const xxx o) const{return x<o.x;}
bool operator > (const xxx o) const{return x>o.x;}
};
vector<xxx> b;
vector<int> f[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--)
{
cin>>m>>n;
for(int i=1;i<=2*n;i++)f[i].clear();
b.clear();
b.push_back((xxx){0,0,0});
cnt=0;
for(int i=1;i<=n;i++)
{
cin>>xx[i]>>yy[i];
b.push_back((xxx){xx[i],i,0});
b.push_back((xxx){yy[i],i,1});
}
sort(b.begin(),b.end());
for(int i=1;i<b.size();i++)
{
if(b[i].x!=b[i-1].x)
{
cnt++;
k[cnt]=b[i].x;
}
if(b[i].z==0)xx[b[i].y]=cnt;
else yy[b[i].y]=cnt;
}
for(int i=1;i<=cnt;i++)f[i].clear();
for(int i=1;i<=n;i++)
f[yy[i]].push_back(xx[i]);
//这里这样初始化是因为在i=1时是没有区间要考虑的
//但是一些d[i][0]又可以从这里转移
//所以这里初始化d[i][1]和s[i][1]
//这样不会有问题
ss[1]=1;//前缀和
s[1][1]=1;
l=1,r=1;
for(int i=2;i<=cnt;i++)
{
if(d[i-1][0]<d[i-1][1])
{
d[i][1]=d[i-1][0]+1;
s[i][1]=s[i-1][0]*(k[i]-k[i-1])%p;
}
else if(d[i-1][0]>d[i-1][1])
{
d[i][1]=d[i-1][1]+1;
s[i][1]=s[i-1][1]*(k[i]-k[i-1])%p;
}
else
{
d[i][1]=d[i-1][0]+1;
s[i][1]=(s[i-1][0]+s[i-1][1])%p*(k[i]-k[i-1])%p;
}
//双指针
for(long long j:f[i])l=max(l,j+1);
while((r<l||d[r+1][1]==d[l][1])&&r<i-1)r++;
ss[i]=(ss[i-1]+s[i][1])%p;
if(r<l)//无法转移,说明方案不存在
{
d[i][0]=1e9;
continue;
}
d[i][0]=d[l][1];
s[i][0]=(ss[r]-ss[l-1]+p)%p;
}
if(d[cnt][1]<d[cnt][0])
cout<<d[cnt][1]<<" "<<s[cnt][1]<<"\n";
else if(d[cnt][1]>d[cnt][0])
cout<<d[cnt][0]<<" "<<s[cnt][0]<<"\n";
else
cout<<d[cnt][1]<<" "<<(s[cnt][0]+s[cnt][1])%p<<"\n";
}
}