POJ 1821_Fence

1.题目相关

· 标签:DP单调队列优化

· 题目地址:http://poj.org/problem?id=1821

· 题目大意:N 块连续的木板,并有 K 个工人来粉刷,但不要求全部粉刷。每个工人有三个参数:L,P,S,表示其最多粉刷连续的 L 块木板,并且每粉刷一块木板可获得 P 元,但所粉刷的木板必须包括第 S 块。输出所能获得最大价值。

 

2.思路

先以 S 为第一关键字排序,建立DP方程

dp[i][j] 表示第 i 个人粉刷到第 j 块木板,所获得最大价值。

dp[i][j] = max{ dp[i-1][j]  //第 i 个人不刷

       dp[i][j-1]  //第 j 面墙不刷

       dp[i-1][k]+(j-k)*P[i]  (j-L[i]<=k<=S[i]-1 && S[i]<=j<=S[i]+L[i]-1)

       }

直接DP会TLE所以要进行一些优化。

对于第一、第二项我们可以做到n^2,所以需要着重优化第三项。

整理后可以发现其可以转化为dp[i-1][k]+k*P[i] 和 j*P[i] 这两项。其中前一项可视为关于 k 的函数,后一项则是常数。并且对于每个 j 来说最优的k 都是递增的,所以就可以用一个值单调递减,位置单调递增的单调队列来维护。一开始把符合条件的k 扫一遍, 并维护队列。在递推时每次查看队头,若当前k 对于 j 不符合,则出队, 直至符合。

 

3.代码

 1 #include<cstdio>

 2 #include<cstdlib>

 3 #include<cstring>

 4 #include<algorithm>

 5 using namespace std;

 6 #define lowbit(a) ((a)&(-a))

 7 #define max(a, b) ((a)>(b)?(a):(b))

 8 #define min(a, b) ((a)<(b)?(a):(b))

 9 #define MAXN 16010

10 #define MAXM 110

11 #define INF 0x777777f

12 typedef long long LL;

13 /*===============Template===============*/

14 struct node{int l, p, s;} a[MAXM];

15 int n, m, le[MAXM], re[MAXM], q[MAXM], dp[MAXM][MAXN];

16 bool cmp(const node &a, const node &b){return a.s<b.s;}

17 void read(){

18     scanf("%d%d", &n, &m);

19     for(int i = 1; i<=m; i++)

20         scanf("%d%d%d", &a[i].l, &a[i].p, &a[i].s);

21     sort(a+1, a+m+1, cmp);

22     for(int i = 1; i<=m; i++){

23         le[i] = max(0, a[i].s-a[i].l);    //递推左边界

24         re[i] = min(n, a[i].s+a[i].l-1);    //递推右边界

25     }

26 }

27 void work(){

28     int i, j, l, p, s, h, t;

29     

30     for(i = 1; i<=m; i++){

31         l = a[i].l;

32         p = a[i].p;

33         s = a[i].s;

34         for(j = 0; j<=re[i]; j++)

35             dp[i][j] = dp[i-1][j];            //先转移第i个人不做

36         h = 1; t = 0;

37         for(j = le[i]; j<a[i].s; j++){        //维护单调队列

38             while(h<=t&&dp[i-1][j]-j*p>=dp[i-1][q[t]]-q[t]*p) t--;

39             q[++t] = j;

40         }

41         for(j = s; j<=re[i]; j++){

42             while(h<t&&j-q[h]>l) h++;    //若不符合则出队

43             dp[i][j] = max(dp[i][j-1], dp[i-1][j]);

44             dp[i][j] = max(dp[i][j], dp[i-1][q[h]]+(j-q[h])*p);

45         }

46         for(j = re[i]+1; j<=n; j++)

47             dp[i][j] = max(dp[i-1][j], dp[i][j-1]);

48     }

49     int ans = 0;

50     for(int i = 1; i<=n; i++)

51         ans = max(ans, dp[m][i]);

52     printf("%d\n", ans);

53 }

54 int main(){

55     read();

56     work();

57     return 0;

58 }    
View Code

 


你可能感兴趣的:(poj)