题解
以前做过很多单调队列优化DP的题。
这个题有一点不同是对于有的状态可以转移,有的状态不能转移。
然后一堆边界和注意点。导致写起来就很难受。
然后状态也比较难定义。
dp[i][j]代表前i个人涂完前j个位置的最大收益。
然后转移考虑
第i个人可以不刷。dp[i][j]=dp[i-1][j];
第j个木板可以不刷dp[i][j]=dp[i][j-1];
然后当c[i].s<=j<=s[i]+l[i]-1时
dp[i][j]=p[i]*j+max(dp[i-1][k]-p[i]*k)其中j-l[i]<=k<=s[i]-1;
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 const int N=20000; 8 const int M=210; 9 int dp[M][N],n,m,q[N],head,tail,ans; 10 struct people{ 11 int l,p,s; 12 }c[M]; 13 bool cmp(people a,people b){ 14 return a.s<b.s; 15 } 16 int read(){ 17 int sum=0,f=1;char ch=getchar(); 18 while(ch<‘0‘||ch>‘9‘){ 19 if(ch==‘-‘)f=-1; 20 ch=getchar(); 21 } 22 while(ch>=‘0‘&&ch<=‘9‘){ 23 sum=sum*10+ch-‘0‘; 24 ch=getchar(); 25 } 26 return sum; 27 } 28 int main(){ 29 while(scanf("%d%d",&n,&m)!=EOF){ 30 memset(dp,0,sizeof(dp)); 31 for(int i=1;i<=m;i++){ 32 c[i].l=read();c[i].p=read();c[i].s=read(); 33 } 34 sort(c+1,c+1+m,cmp); 35 for(int i=1;i<=m;i++){ 36 memset(q,0,sizeof(q)); 37 head=1;tail=1; 38 for(int j=1;j<=n;j++){ 39 dp[i][j]=max(dp[i-1][j],dp[i][j-1]); 40 if(j>=c[i].s&&j<=c[i].s+c[i].l-1){ 41 while(head<=tail&&q[head]<j-c[i].l)head++; 42 if(head>tail)continue; 43 dp[i][j]=max(c[i].p*j+dp[i-1][q[head]]-c[i].p*q[head],dp[i][j]); 44 } 45 if(j<c[i].s){ 46 while(head<=tail&&dp[i-1][j]-c[i].p*j>=dp[i-1][q[tail]]-c[i].p*q[tail])tail--; 47 q[++tail]=j; 48 } 49 } 50 } 51 printf("%d\n",dp[m][n]); 52 } 53 return 0; 54 }
原文地址:https://www.cnblogs.com/Xu-daxia/p/9757131.html
时间: 2024-11-01 16:18:00