poj1821 Fence

题目描述

题解:

应该是个$dp$;

$dp[i][j]$表示第$i$个人涂到第$j$块的最大收益。

推一下式子:$$dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][k]+(j-k)*p[i])$$

对于最后面那个式子可以化一下:$$max(dp[i-1][k]+(j-k)*p[i])=max(dp[i-1][k]-k*p[i])+j*p[i]$$

然后发现这是个单调队列优化dp。

搞一下$k$的范围就结束了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 16050
#define K 105
#define ll long long
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,k;
struct edc
{
    int l,p,s;
}o[K];
bool cmp(edc a,edc b){return a.s<b.s;}
ll dp[K][N];
int sta[N],hd,tl;
int main()
{
    while(scanf("%d%d",&n,&k)>0)
    {
    for(int i=1;i<=k;i++)
        o[i].l=rd(),o[i].p=rd(),o[i].s=rd();
    sort(o+1,o+1+k,cmp);
    for(int i=1;i<=k;i++)
    {
        hd=1,tl=1;
        sta[1]=0;
        for(int j=1;j<=n;j++)
        {
            dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            while(hd<=tl&&sta[hd]<j-o[i].l)hd++;
            if(hd<=tl&&j>=o[i].s)dp[i][j]=max(dp[i][j],dp[i-1][sta[hd]]+1ll*(j-sta[hd])*o[i].p);
            if(j<o[i].s)
            {
                while(hd<=tl&&(dp[i-1][sta[tl]]-sta[tl]*o[i].p)<(dp[i-1][j]-j*o[i].p))tl--;
                sta[++tl]=j;
            }
        }
    }
    printf("%lld
",dp[k][n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10206815.html