您的位置:首页 > 其它

[CodeForces-721E]Road to Home

2017-10-10 19:21 477 查看

题目大意:
  一条长度为L的路上有n个路灯,每个路灯能照亮的范围互不重叠。
  现在你要一边走路一边唱歌,唱一首歌的同时可以走p的路程。
  你要么一直唱下去,要么停一会继续唱,一首歌必须唱完才能停下。
  歌唱一旦停止,就至少经过t的路程才能继续唱。
  为了不伤及无辜,你不能在黑的地方唱歌。
  问最多能唱多少首歌。

思路:
  很容易想到一个O(n^2)的DP。
  用f[i]表示走完第i个路灯能唱的歌数,用g[i]表示走完第i个路灯并唱完f[i]首歌能走到的位置。
  状态转移方程:
  f[i]=max{f[j]+r-max(l,g[j]+t)/p}
  g[i]=max{r-(r-max(l,g[j]+t))%p}
  这样会在第14个点TLE,考虑把转移优化成O(1)的:
  如果i的答案不够优,我们就用i-1的答案代替i。
  很显然,f和g都是单调不下降的。
  一个状态j可以被转移到i当且仅当x<=j<=y。
  其中x表示满足g[x]+t<=l的最后一个状态;
  y表示满足g[x]+t<=r的最后一个状态。
  所以我们每次只需要从j转移过来即可。
  除了x和y会被转移两次,其它都只会转移一次,所以时间复杂度是O(n)的。
  另外需要注意当转移前后的f相等时,g更小的更优,要转移过去,否则会在第14个点WA。

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=100001;
int f
,g
;
int main() {
const int L=getint(),n=getint(),p=getint(),t=getint();
g[0]=-t;
for(register int i=1,j=0;i<=n;i++) {
const int l=getint(),r=getint();
while(j<i&&g[j]+t<=r) {
if(f[j]+(r-std::max(l,g[j]+t))/p>f[i]||f[j]+(r-std::max(l,g[j]+t))/p==f[i]&&r-(r-std::max(l,g[j]+t))%p<g[i]) {
f[i]=f[j]+(r-std::max(l,g[j]+t))/p;
g[i]=r-(r-std::max(l,g[j]+t))%p;
}
j++;
}
j--;
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\n",f
);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: