正题
题目链接:http://poj.org/problem?id=1821
题目大意
有n个木板,m个工人,每个木板只能被粉刷一次,第i个工人如果刷的话必须刷木板SiSi,连续的不超过LiLi的,没一块PiPi。
解题思路
用fi,jfi,j表示前j块木板,前i个工人最大价值,然后如果什么都不做就是fi−1,jfi−1,j,也可以空着不刷fi,j−1fi,j−1。然后我们就在1∼Li1∼Li的范围内找到
fi,j=maxj−Li≤k≤Si−1{fi−1,j+Pi∗(j−k)}(j≥Si)fi,j=maxj−Li≤k≤Si−1{fi−1,j+Pi∗(j−k)}(j≥Si)
然后用单调队列维护k就好了。
code
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct node{int l,p,s;
}a[110];
int n,m,f[110][16010];
deque<int> q;
bool cmp(node x,node y)
{return x.s<y.s;}
int calc(int i,int k){return f[i-1][k]-a[i].p*k;
}
int main()
{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);sort(a+1,a+m+1,cmp);for(int i=1;i<=m;i++){while(!q.empty())q.pop_back();for(int k=max(0,a[i].s-a[i].l);k<=a[i].s-1;k++){while(!q.empty()&&calc(i,q.back())<=calc(i,k)) q.pop_back();q.push_back(k);}//加入元素for(int j=1;j<=n;j++){f[i][j]=max(f[i-1][j],f[i][j-1]);//啥都不干if(j>=a[i].s){while(!q.empty()&&q.front()<j-a[i].l) q.pop_front();//维护区域if(!q.empty()) f[i][j]=max(f[i][j],calc(i,q.front())+a[i].p*j);//统计答案}}}printf("%d",f[m][n]);
}