poj 1821 Fence 单调队列优化dp

/* poj 1821 n*n*m 暴力*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 110
#define maxm 16010
using namespace std;
int n,m,f[maxn][maxm],ans;
struct node{
    int l,s,p;
    bool operator < (const node &x) const {
        return s<x.s;
    }
}a[maxn];
int max(int x,int y){
    return x>y?x:y;
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&a[i].l,&a[i].p,&a[i].s);
        memset(f,0,sizeof(f));ans=0;
        sort(a+1,a+1+m);//排序s为关键字 
        for(int i=1;i<=m;i++){//状态表示 前i个人 干到j这里 的最优值 
            int x=min(n,a[i].s+a[i].l-1);//i最多干到哪 
            for(int j=1;j<=n;j++){
                f[i][j]=max(f[i][j-1],f[i-1][j]);//i不干j 可以是j-1的状态 也可以是上一个人干到j的状态 
                if(j<a[i].s||j>x)continue;//i必须停在这个范围里 也就是状态在这个范围 
                for(int k=0;k<a[i].s;k++){//上一个人 i-1 他不能把i的起点覆盖了 否则i就走不了了 
                    if(j-k>a[i].l)continue;//i要把k-j的都盖了 长度有限制 
                    f[i][j]=max(f[i][j],f[i-1][k]+(j-k)*a[i].p);
                }
                ans=max(ans,f[i][j]);
            }    
        }
        printf("%d\n",ans);
    }
    
    return 0;
}
/* 
poj 1821 单调队列优化
wa到挺了.....
一开始队列指针写错了...
好吧平时用STL最近手打在改习惯改乱了.
开始一直混乱着
不知道怎么保证队列里存的是i-1的状态而不是i的
根据方程的含义来看 上次不能盖了这次的s 这次还至少到s
正好分开了 多以存的时候分开
第一个for是存i-1的状态
后一个是更新i 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 110
#define maxm 16010
using namespace std;
int n,m,f[maxn][maxm],ans;
int q[maxm],head,tail;
struct node{
    int l,s,p;
    bool operator < (const node &x) const {
        return s<x.s;
    }
}a[maxn];
int max(int x,int y){
    return x>y?x:y;
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&a[i].l,&a[i].p,&a[i].s);
        memset(f,0,sizeof(f));ans=0;
        sort(a+1,a+1+m);
        for(int i=1;i<=m;i++){
            head=1;tail=0;
            for(int j=1;j<=n;j++)
                f[i][j]=max(f[i-1][j],f[i][j-1]);
            int L=max(0,a[i].s-a[i].l);
            int R=min(n,a[i].s+a[i].l-1);
            for(int j=L;j<a[i].s;j++){
                int x=f[i-1][j]-j*a[i].p;
                while(head<=tail&&f[i-1][q[tail]]-q[tail]*a[i].p<x)tail--;
                q[++tail]=j;
            }
            for(int j=a[i].s;j<=R;j++){
                while(head<=tail&&j-q[head]>a[i].l)head++;
                int y=q[head];
                f[i][j]=max(f[i][j],f[i-1][y]+(j-y)*a[i].p);//这里要取大 
                ans=max(ans,f[i][j]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2016-10-17 16:06  一入OI深似海  阅读(219)  评论(0编辑  收藏  举报