Machine Works UVALive - 5133
超哥线段树优化Dp
题解:
裸方程很好想:
fi=max{fj+Gj∗(Di−Dj−1}−Pi+Ri
当前面的max小于Pi的时候fi=−inf.
时间复杂度:O(n2).
其实就是维护一次函数的最大值。
直接超哥线段树即可。
正解好像是单调队列 ?
Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
typedef long long ll;
typedef long double ld;
const ll INF = 1e18;
const int N = 100005;
const int mxn = 1e9;
ll C,D,f[N];
int n,sz,root,lch[N*30],rch[N*30];
ll K[N*30],B[N*30];
struct Machine{
ll d,p,r,g;
} m[N];
bool cmp(const Machine &a, const Machine &b){
return a.d < b.d;
}
inline ll getB(ll k,ll x,ll y){ return y-k*x; }
inline bool better(ll k1,ll b1,ll k2,ll b2,ll x){ return k1*x+b1 > k2*x+b2; }
void insert(int &x,int l,int r,ll k,ll b){
if(!x) x=++sz;
if(l==r){
if(better(k,b,K[x],B[x],l)){ K[x]=k; B[x]=b; }
return;
}
else{
int mid=(l+r)>>1;
if(k > K[x]){
if(better(k,b,K[x],B[x],mid)){
swap(K[x],k); swap(B[x],b);
insert(lch[x],l,mid,k,b);
}
else insert(rch[x],mid+1,r,k,b);
}
else{
if(better(k,b,K[x],B[x],mid)){
swap(K[x],k); swap(B[x],b);
insert(rch[x],mid+1,r,k,b);
}
else insert(lch[x],l,mid,k,b);
}
}
}
ll query(int x,int l,int r,int p){
if(!x) return 0.0;
ll d=K[x]*p+B[x];
if(l==r) return d;
else{
int mid=(l+r)>>1;
if(p<=mid) return max(d,query(lch[x],l,mid,p));
else return max(d,query(rch[x],mid+1,r,p));
}
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int cas=0;
while(scanf("%d%lld%lld",&n,&C,&D)!=EOF && (n||C||D)){
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld%lld",&m[i].d,&m[i].p,&m[i].r,&m[i].g);
}
sort(m+1,m+1+n,cmp);
// for(int i=1;i<=n;i++){
// printf("d = %d p = %d r = %d g = %d\n",m[i].d,m[i].p,m[i].r,m[i].g);
// }
insert(root,1,mxn,0,C);
int last=0;
for(int i=1;i<=n;i++){
if(i>1 && m[i-1].d!=m[i].d){
for(int j=last+1;j<=i-1;j++){
if(f[j]!=-1) insert(root,1,mxn,m[j].g,getB(m[j].g,m[j].d,f[j]));
}
last=i-1;
}
f[i]=query(root,1,mxn,m[i].d-1);
// D(f[i]);
if(f[i]>=m[i].p) f[i]+=m[i].r-m[i].p;
else f[i]=-1;
// D(f[i]); E;
// cout<<f[i]<<endl;
}
ll ans=C;
for(int i=1;i<=n;i++){
if(f[i]!=-1) ans=max(ans, f[i]+m[i].g*(D-m[i].d));
}
printf("Case %d: %lld\n",++cas,ans);
}
}