您的位置:首页 > 产品设计 > UI/UE

[bzoj4658]rescue

2017-01-16 10:34 369 查看

题目描述

wyh8000很喜欢看书,特别是那种很容易死脑细胞的书。

wyh8000看书喜欢从第K页开始看起,然后看到第M页,但是wvh8000并不是有耐心的小盆友,他

只想快点完成看书任务,然后就可以去愉快的农别人了,于是他经常跳着看,但是他一次最多跳D页,

然后阅读那一页的内容,然后死掉A的脑细胞。当然如果那一页的内容他比较感兴趣,又会回复一定

的脑细胞。

好心的学长不希望看到wyh8000的脑细胞死光,你能帮助wvh8000死掉尽可能少的脑细胞吗?

DP

关键点才有用嘛……

设f[i]表示看第i个关键点死的最少脑细胞。

f[i]=min(f[j]+⌈Ti−TjD⌉∗A)−bi

这个DPn^2

然后该往哪个方向思考呢?你注意两个T同时+D相对关系还是不变,看来和模有关了。

把Ti表示为Ci*D+Ei(0<=Ei<D)

然后发现原式变成

f[i]=min(f[j]+(Ci−Cj+⌈Ei−EjD⌉)∗A)−bi

只有Ei>Ej才产生1的贡献。

好咯,根据E为下标维护线段树即可。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10,maxtot=3500000+10,maxd=1e9;
ll left[maxtot],right[maxtot];
ll tree[maxtot];
ll T[maxn],b[maxn],c[maxn],e[maxn];
ll f[maxn];
ll i,j,k,l,t,n,m,tot,root,A,D;
ll read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void change(ll &x,ll l,ll r,ll a,ll b){
if (!x) x=++tot,tree[x]=1e18;
if (l==r){
tree[x]=min(tree[x],b);
return;
}
ll mid=(l+r)/2;
if (a<=mid) change(left[x],l,mid,a,b);else change(right[x],mid+1,r,a,b);
tree[x]=min(tree[left[x]],tree[right[x]]);
}
ll query(ll x,ll l,ll r,ll a,ll b){
if (!x||a>b) return 1e18;
if (l==a&&r==b) return tree[x];
ll mid=(l+r)/2;
if (b<=mid) return query(left[x],l,mid,a,b);
else if (a>mid) return query(right[x],mid+1,r,a,b);
else return min(query(left[x],l,mid,a,mid),query(right[x],mid+1,r,mid+1,b));
}
int main(){
k=read();m=read();D=read();A=read();n=read();
fo(i,1,n) T[i]=read(),b[i]=read();
T[0]=k;T[++n]=m;
fo(i,0,n){
c[i]=T[i]/D;
e[i]=T[i]%D;
}
tree[0]=1e18;
change(root,0,D-1,e[0],-c[0]*A);
fo(i,1,n){
f[i]=1e18;
j=query(root,0,D-1,0,e[i]-1);
f[i]=min(f[i],j+A+c[i]*A-b[i]);
j=query(root,0,D-1,e[i],D-1);
f[i]=min(f[i],j+c[i]*A-b[i]);
change(root,0,D-1,e[i],f[i]-c[i]*A);
}
printf("%lld\n",-f
);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: