[USACO08MAR]土地徵用Land Acquisition
阿新 • • 發佈:2018-12-21
這個題直接上斜率優化吧……
因為對答案有貢獻的是長或者寬最大的那個。所以我們首先按一維排序,這樣我們就只需要考慮另一維了。
考慮用dp[i]表示購買前i塊土地的最小費用,那麼我們可以很容易的得到dp方程:
\[dp[i] = min_{j=1}^{i-1}dp[j] + x[j+1] * y[i]\]
注意這個方程得到之前需要先對原序列處理。因為能對答案有貢獻的是最大的值,所以我們在排序以後需要對序列線性掃描一次,只把比當前最大值大的加入序列。(所以只要取j+1)即可。
考慮斜率優化。我沒有采用線性規劃一樣的方法……我們考慮兩個決策p,q,其中q在p的後面。當q比p優的時候我們把式子列出來移項轉化。這樣得到以下結論:
\(\frac{dp[q] - dp[p]}{y[p+1] - y[q+1]} < x[i]\)
這樣我們就進行斜率優化就好了。具體的可以看這篇:HNOI2008 玩具裝箱Toy
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<vector> #include<map> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') #define fr friend inline #define y1 poj #define mp make_pair #define pr pair<int,int> #define fi first #define sc second #define pb push_back using namespace std; typedef long long ll; const int M = 50005; const int INF = 1000000009; const double eps = 1e-7; ll read() { ll ans = 0,op = 1;char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();} while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar(); return ans * op; } struct node { ll val,pos; }q1[M]; struct land { ll x,y; bool operator < (const land &g)const { if(y == g.y) return x > g.x; return y > g.y; } }a[M],t[M]; ll n,dp[M],q[M],head,tail,tot; double slope(ll p,ll q) { return (double)((dp[q] - dp[p]) / (a[p+1].y - a[q+1].y)); } int main() { n = read(); rep(i,1,n) t[i].x = read(),t[i].y = read(); sort(t+1,t+1+n); rep(i,1,n) if(t[i].x > a[tot].x) a[++tot] = t[i]; rep(i,1,tot) { while(head < tail && slope(q[head],q[head+1]) <= a[i].x) head++; dp[i] = dp[q[head]] + a[i].x * a[q[head]+1].y; while(head < tail && slope(q[tail-1],q[tail]) >= slope(q[tail],i)) tail--; q[++tail] = i; } printf("%lld\n",dp[tot]); return 0; }