[Usaco2008 Mar]土地购买 斜率优化DP

以为是智商题,想了一天

试着把矩形去重后保留了单调减的长和单调增的宽,推出了一个DP转移方程,

猜是和满足单峰性质试着三分写了一发wa了,果然不是单峰性质的

之后感觉转移方程像一次函数就想到维护凸包,试探性地搜了关键字usaco和斜率优化发现这题果然是。。

然后就学了学斜率优化DP

自己推出来直线的性质还是比较好理解的

每个矩形都可以看做一个一次函数,长为斜率,dp值为高

主要就是转移反应在两条直线的交点左右两侧不同,始终选在下面那段线段转移过来是最优的,

这就要求在加入直线的时候始终保持变动点坐标的单调递增

如果新的变动点比之前某个变动点坐标小,画画图会发现弹掉一条之前的直线会有更好的下段线段供转移

 1 //#include<bits/stdc++.h>  
 2 //#pragma comment(linker, "/STACK:1024000000,1024000000")   
 3 #include<stdio.h>  
 4 #include<algorithm>  
 5 #include<queue>  
 6 #include<string.h>  
 7 #include<iostream>  
 8 #include<math.h>                    
 9 #include<stack>
10 #include<set>  
11 #include<map>  
12 #include<vector>  
13 #include<iomanip> 
14 #include<bitset>
15 
16 using namespace std;         //
17 
18 #define ll long long  
19 #define ull unsigned long long
20 #define pb push_back  
21 #define FOR(a) for(int i=1;i<=a;i++) 
22 #define sqr(a) (a)*(a)
23 #define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
24 ll qp(ll a,ll b,ll mod){
25     ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t;
26 }
27 struct DOT{int x;int y;};
28 inline void read(int &x){int k=0;char f=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())k=k*10+c-'0';x=k*f;} 
29 void ex(){puts("-1");exit(0);}
30 const int dx[4]={0,0,-1,1};
31 const int dy[4]={1,-1,0,0};
32 const int inf=0x3f3f3f3f; 
33 const ll Linf=0x3f3f3f3f3f3f3f3fLL;
34 const ll Mod=1e18+7;
35 const double eps=1e-6;
36 const double pi=acos(-1.0);
37 
38 const int maxn=5e4+33;
39 
40 int n;
41 
42 struct NODE{
43     int x,y;
44 }a[maxn];
45 
46 bool cmp(NODE lx,NODE rx){
47         if(lx.x==rx.x)return lx.y>rx.y;
48         return lx.x>rx.x;
49 }
50 
51 ll dp[maxn];
52 
53 int q[maxn];
54 
55 double bias(int j,int k){    //k better j
56     return (1.0*dp[j]-dp[k])/(1.0*a[k+1].x-a[j+1].x);
57 }
58 
59 int main(){
60     scanf("%d",&n);
61     for(int i=1;i<=n;i++){
62         scanf("%d%d",&a[i].x,&a[i].y);
63     }
64     sort(a+1,a+1+n,cmp);
65     int tot=1;
66     for(int i=2;i<=n;i++){
67         if(a[i].x<=a[tot].x && a[i].y<=a[tot].y)continue;
68         a[++tot]=a[i];
69     }
70     
71     int l=0,r=0;
72     for(int i=1;i<=tot;i++){
73         while(l<r && bias(q[l],q[l+1])<a[i].y){
74             l++;
75         }
76         dp[i]=dp[q[l]]+1ll*a[q[l]+1].x*a[i].y;
77         while(l<r && bias(q[r-1],q[r])>bias(q[r],i)){
78             r--;
79         }
80         q[++r]=i;
81     }
82 
83     printf("%lld
",dp[tot]);
84 }
View Code
原文地址:https://www.cnblogs.com/Drenight/p/8869870.html