题目大意:有k个工人,有一排n个砖头,现在要给砖头染色,每个工人要么不染色,要么选择一个包含$s_{i}$的,长度不大于$l_{i}$的区域进行染色,然后他们会获得$lencdot p_{i}$的报酬,求使所有工人总报酬最大的方案,输出最大报酬
定义$f[i][j]$表示已经遍历到了第i个工人,遍历到了第j块砖头的最大报酬
显然$f[i][j]=max(f[i-1][j],f[i][j-1],f[i-1][k]+(j-k)p_{i})$
展开$f[i-1][k]+(j-k)p_{i}=f[i-1][k]-kcdot p_{i}+jcdot p_{i}$,发现$f[i-1][k]-kcdot p_{i}$具有单调性,用单调队列优化即可
注意能使用队列优化转移的区间必须包含$s_{i}$
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define N1 16010 5 #define M1 105 6 #define ll long long 7 using namespace std; 8 9 int K,n; 10 ll f[2][N1]; 11 int que[N1]; 12 struct node{int l,w,s;}a[M1]; 13 int cmp(node s1,node s2) 14 {return s1.s<s2.s;} 15 16 int main() 17 { 18 while(scanf("%d%d",&n,&K)!=EOF) 19 { 20 int now=1,pst=0; 21 for(int i=1;i<=K;i++) 22 scanf("%d%d%d",&a[i].l,&a[i].w,&a[i].s); 23 sort(a+1,a+K+1,cmp); 24 for(int i=1;i<=K;i++) 25 { 26 int hd=1,tl=0; 27 memset(f[now],0,sizeof(f[now])); 28 if(a[i].s-a[i].l<=0&&0<a[i].s) que[++tl]=0; 29 for(int j=1;j<=n;j++) 30 { 31 while(hd<=tl&&(j-que[hd]>a[i].l)) 32 hd++; 33 f[now][j]=max(max(f[pst][j],f[now][j-1]),(hd<=tl&&j>=a[i].s)?(f[pst][que[hd]]+1ll*a[i].w*(j-que[hd])):0ll); 34 if(j<a[i].s-a[i].l||j>=a[i].s) continue; 35 while(hd<=tl&&f[pst][j]-a[i].w*j>=f[pst][que[tl]]-a[i].w*que[tl]) 36 tl--; 37 que[++tl]=j; 38 }swap(now,pst); 39 } 40 printf("%lld ",f[pst][n]); 41 memset(f,0,sizeof(f)); 42 memset(a,0,sizeof(a)); 43 memset(que,0,sizeof(que)); 44 } 45 return 0; 46 }