【题目大意】
有一条长为l的公路(可看为数轴),n盏路灯,每盏路灯有照射区间且互不重叠,有个人要走过这条公路,他只敢在路灯照射的地方唱歌,固定走p唱完一首歌,歌曲必须连续唱否则就要至少走t才能继续唱,按序给出路灯照射范围
【解题思路】
简单可证对于一段照射区间要么不唱歌要么能唱多久唱多久
DP,f[i]表示前i段最多能唱几首歌,g[i]表示在唱f[i]首歌的情况下最早在什么时候可以停止唱歌
m=(r[i]-max(g[j]+t,l))/p
f[i]=max(f[j]+m)
g[i]=min(g[i],max(g[j]+t,l)+m*p)
因为g[]具有单调性,所以处理i时只要从j(g[j]+t∈[l[i],r[i]))转移就行了,剩下的可以全部通过f[i]=max(f[i],f[i-1])快速转移
时间复杂度O(N)
【一段废话】
题目看完感觉应该是dp,然后就开始找单调性,结果越想越复杂,思路还一直被这题的其中一个tag“二分”带跑,然后看完题解后感觉自己简直智障,哎,果然智商低的人是做不了OI的
【呆马】
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
using namespace std;
int l,n,p,t,i,j,x,y,v,L,f[100001],g[100001];
int main()
{
scanf("%d%d%d%d\n",&l,&n,&p,&t);
g[0]=-t;
for (i=j=1;i<=n;i++)
{
scanf("%d%d\n",&x,&y);
j--;
for (;j<i && g[j]+t<=y;j++)
{
L=max(x,g[j]+t);
v=(y-L)/p+f[j];
if (v>f[i] || (v==f[i] && L+(y-L)/p*p<g[i])) f[i]=v,g[i]=L+(y-L)/p*p;
}
if (f[i-1]>f[i] || (f[i-1]==f[i] && g[i-1]<g[i])) f[i]=f[i-1],g[i]=g[i-1];
}
printf("%d",f[n]);
}