3
17
2016
1

Diary of March 17th

UPD 7:09 跪求今天模拟赛也能考的好点…
UPD 18:11 不浪了来更博客了……今天考的也还可以 果然灵验
话说 我这样用RP 省选会不会爆蛋啊

这道是2011WF原题
昨天鼎爷的模拟赛出了这题
然而虽然当时我看出来是斜率优化DP 然而理解太浅
以为和前几道斜率优化DP是一样的 所以就爆蛋了
首先 $dp_i$ 表示买入第 $i$ 个机器前最多能有多少钱
我们把机器按照 $d$ 排序,那么转移方程就是
$dp_i=max\{dp_j-p_j+r_j+g_j*(d_i-d_j-1)\}$
可以移项,就变成了
$dp_i=max\{g_j*d_i+dp_j-p_j+r_j-g_j*(d_j+1)\}$
再移一下就变成了
$dp_j-p_j+r_j-g_j*(d_j+1)=-d_i*g_j+dp_i$
然后我们就可以把$d_i$看成斜率 $k$ ,把$g_j$看成 $x$ 坐标,
再把$dp_j-p_j+r_j-g_j*(d_j+1)$看成 $y$ 坐标
也就是
$y=kx+dp_i$
也就是相当于有一条斜率为 $k$ 的直线从正无穷扫下来,
要让$dp_i$尽量大,取它遇到的第一个点 这是最优答案
算出来当前的$dp_i$之后如果买的起这台机器就把$(X_i,Y_i)$加到坐标系里面去。
然而如果按 $d$ 排序的话 $x$ 坐标不是递增,于是可以按 $g$ 排序
因为最优解里面 $g$ 肯定是单调递增的 所以对答案是没有影响的
这样的话就可以维护一个单调栈,每次询问二分就可以了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<ctime>
#include<cstdlib>
#include<string>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<bitset>
#define Rep(x,a,b) for (int x=a;x<=b;x++)
#define Drp(x,a,b) for (int x=a;x>=b;x--)
#define Cross(x,a) for (int x=head[a];~x;x=next[x])
#define ll long long
#define oo (1<<29)
#define mk(a,b) make_pair(a,b)
#define fr first
#define sc second
#define db double
using namespace std;
inline int IN(){
	int x=0,ch=getchar(),f=1;
	while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
	if (ch=='-'){f=-1;ch=getchar();}
	while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
inline void OUT(ll x){
	if (x<0) putchar('-'),x=-x;
	if (x>=10) OUT(x/10),putchar(x%10+'0');
		else putchar(x+'0');
}
const int N=100005;
int n,c,d;
struct Machine{
	int d,r,p,g;
	bool operator <(const Machine&x)const{return g<x.g;}
}a[N];
ll dp[N];
int Cs,s[N],top;
db Y(int j,int k){
	db ret=dp[j]-dp[k]-a[j].p+a[k].p+a[j].r-a[k].r-1ll*a[j].g*(a[j].d+1)+1ll*a[k].g*(a[k].d+1);
	return ret;
}
db X(int j,int k){
	db ret=a[j].g-a[k].g;
	return ret;
}
int Get(db k){
	if (top==1) return 1;
	int l=1,r=top-1;
	if (Y(s[l+1],s[l])/X(s[l+1],s[l])<=k) return l;
	if (Y(s[r+1],s[r])/X(s[r+1],s[r])>=k) return r+1;
	while (l<r){
		int mid=l+r>>1;
		if (Y(s[mid+1],s[mid])/X(s[mid+1],s[mid])>=k) l=mid+1;
			else r=mid;
	}
	return l;
}
int main(){
	freopen("works.in","r",stdin);
	freopen("works.out","w",stdout);
	while (scanf("%d%d%d",&n,&c,&d)){
		if (!n&&!c&&!d) return 0;
		Rep(i,1,n) a[i].d=IN(),a[i].p=IN(),a[i].r=IN(),a[i].g=IN();
		a[n+1].d=d+1;
		sort(a+1,a+n+1);
		dp[0]=c;
		top=0,s[++top]=0;
		Rep(i,1,n+1){
			int j=Get((db)(-a[i].d));
			dp[i]=dp[s[j]]-a[s[j]].p+a[s[j]].r+1ll*a[s[j]].g*(a[i].d-a[s[j]].d-1);
			if (i==n+1) break;
			if (dp[i]>=a[i].p){
				while (top>1&&Y(i,s[top])/X(i,s[top])>=Y(s[top],s[top-1])/X(s[top],s[top-1])) top--;
				s[++top]=i;
			}
		}
		printf("Case %d: ",++Cs);OUT(dp[n+1]),putchar('\n');
	}
}

 

Category: Diary | Tags: 凸包 DP | Read Count: 446
pavzi.com 说:
Jan 08, 2024 06:11:49 PM

Pavzi.com provides all the news about Gadgets, the Economy, Technology, Business, Finance and many more. The main concept or our aim behind this website has been the will to provide resources with full information on each topic which can be accessed through the Internet. To ensure that every reader gets what is important and worthy about the topic they search and link to hear from us. pavzi.com Our site is a multiple Niche or category website which will ensure to provide information and resources on each and every topic. Some of the evergreen topics you will see on our website are Career, Job Recruitment, Educational, Technology, Reviews and others. We are targeting mostly so it is true that Tech, Finance, and Product Reviews. The only reason we have started this website is to make this site the need for your daily search use.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com