题意大致是有k个粉刷匠,要粉刷n面墙,分别站在某一面墙si的前面,他们每个人只愿意刷li面墙,而且每刷一面需要给pi的工钱,题目要求最多能发多少工钱。
思路:斜率优化dp
思路跟http://www.cnblogs.com/yzcstc/articles/2870355.html这里面说的差不多
1 /* 2 State:Accepted 3 Time:2013-03-11 23:03:01 4 */ 5 #include <iostream> 6 #include <cstring> 7 #include <string> 8 #include <cstdlib> 9 #include <cstdio> 10 #include <algorithm> 11 #include <cmath> 12 #include <queue> 13 using namespace std; 14 struct oo{ int l, p , s; }; 15 int n , k; 16 int f[120][16010], q[100000] ,le[150], re[150]; 17 oo worker[150]; 18 19 bool cmp(const oo a , const oo b){ return a.s < b.s; } 20 void init() 21 { 22 scanf("%d%d",&n, &k); 23 for (int i = 1; i <= k ; ++i) 24 scanf("%d%d%d",&worker[i].l , &worker[i].p, &worker[i].s); 25 sort(worker + 1, worker + 1 +k, cmp); 26 for (int i = 1; i <= k; ++i){ 27 le[i] = max(0 ,worker[i].s - worker[i].l); 28 re[i] = min(n ,worker[i].s + worker[i].l - 1); 29 } 30 } 31 32 void dp() 33 { 34 35 int l , s , p , h ,t; 36 for (int i = 1; i <= k ; ++i) 37 { 38 l = worker[i].l; 39 s = worker[i].s; 40 p = worker[i].p; 41 for (int j = 0; j <= re[i]; ++j) 42 f[i][j] = f[i-1][j]; 43 h =1; 44 t = 0; 45 for (int j = le[i]; j < s; ++j) 46 { 47 while (t >= h && f[i-1][j] - j*p >= f[i-1][q[t]] - q[t]*p) --t; 48 q[++t] = j; 49 } 50 for (int j = s; j <= re[i]; ++j) 51 { 52 while (t > h && j - q[h] > l) ++h; 53 f[i][j] = max(f[i][j-1], f[i-1][j]); 54 f[i][j] = max(f[i][j] , f[i-1][q[h]] + (j-q[h])*p); 55 } 56 for (int j = re[i]+1; j <=n ; ++j) 57 f[i][j] = max(f[i-1][j], f[i][j-1]); 58 } 59 int ans = 0; 60 for (int i = 1; i <= n ; ++i) 61 ans = max(ans , f[k][i]); 62 printf("%d\n",ans); 63 } 64 65 66 int main(){ 67 freopen("poj1821.in","r",stdin); 68 freopen("poj1821.out","w",stdout); 69 init(); 70 dp(); 71 }