BZOJ3963 WF2011MachineWorks(動態規劃+斜率優化+cdq分治)
阿新 • • 發佈:2019-01-15
end read for div -- pan pac 優化 etc
按賣出時間排序後,設f[i]為買下第i臺機器後的當前最大收益,則顯然有f[i]=max{f[j]+gj*(di-dj-1)+rj-pi},且若此值<0,應設為-inf以表示無法購買第i臺機器。
考慮優化,顯然是一個斜率優化式子,設j轉移優於k,則f[j]+gj(di-dj-1)+rj>f[k]+gk(di-dk-1)+rk,移項得(f[j]-gjdj-gj+rj)-(f[k]-gkdk-gk+rk)>di(gk-gj)。g沒有單調性,於是cdq分治,按g排序建上凸殼即可。
註意比較斜率時只能用long double,因為乘法會溢出。對於橫坐標相同的點需要特判一下,如果加進去的點縱坐標較大就把之前的點彈掉。感覺每次寫斜率優化對這種問題都毫無辦法。復雜度O(nlogn)。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 100010 #define inf 2000000000000000000ll char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f; } int T,n,m,k,q[N]; struct data { int d,p,r,g,i;ll ans; bool operator <(const data&a) const { return d<a.d; } }a[N],b[N]; ll calc(int i){return a[i].ans-1ll*a[i].g*(a[i].d+1)+a[i].r;} bool check(int x,int y,int i) { if (a[i].g==a[y].g) return calc(i)>=calc(y); return (long double)(calc(i)-calc(y))/(a[i].g-a[y].g)>=(long double)(calc(y)-calc(x))/(a[y].g-a[x].g); } void solve(int l,int r) { if (l>=r) return; int mid=l+r>>1; solve(l,mid); int head=1,tail=0; for (int i=l;i<=mid;i++) { while (tail>1&&check(q[tail-1],q[tail],i)) tail--; q[++tail]=i; } for (int i=mid+1;i<=r;i++) { while (head<tail&&calc(q[head+1])-calc(q[head])>-1ll*a[i].d*(a[q[head+1]].g-a[q[head]].g)) head++; if (calc(q[head])+1ll*a[q[head]].g*a[i].d-a[i].p>=0) a[i].ans=max(a[i].ans,calc(q[head])+1ll*a[q[head]].g*a[i].d-a[i].p); } solve(mid+1,r); int i=l,j=mid+1; for (int k=l;k<=r;k++) if (i<=mid&&a[i].g<a[j].g||j>r) b[k]=a[i++]; else b[k]=a[j++]; for (int k=l;k<=r;k++) a[k]=b[k]; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3963.in","r",stdin); freopen("bzoj3963.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),k=read(); while (n) { for (int i=1;i<=n;i++) a[i].d=read(),a[i].p=read(),a[i].r=read(),a[i].g=read(),a[i].i=i; n++,a[n].d=k+1,a[n].p=a[n].r=a[n].g=0; sort(a+1,a+n+1); for (int i=1;i<=n;i++) a[i].ans=-inf;a[0].ans=m; solve(0,n); for (int i=1;i<=n;i++) a[0].ans=max(a[0].ans,a[i].ans); printf("Case ");printf("%d",++T);printf(": ");printf(LL,a[0].ans); n=read(),m=read(),k=read(); } return 0; }
BZOJ3963 WF2011MachineWorks(動態規劃+斜率優化+cdq分治)