POJ1821Fence

题目

题目

思路

显然的dp方程:(设dp[i][j]为前i个人干前j个方块的最大值)
d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] , m a x ( d p [ i − 1 ] [ k ] + p [ i ] ∗ ( j − k ) ( m a x ( 0 , s [ i ] − l [ i ] ) < = k < = m i n ( j , s [ i ] − 1 ) ) dp[i][j]=max(dp[i][j-1],dp[i-1][j],max(dp[i-1][k]+p[i]*(j-k)(max(0,s[i]-l[i])<=k<=min(j,s[i]-1)) dp[i][j]=max(dp[i][j1],dp[i1][j],max(dp[i1][k]+p[i](jk)(max(0,s[i]l[i])<=k<=min(j,s[i]1))
发现第3个部分可以优化,化为 d p [ i − 1 ] [ k ] − p [ i ] ∗ k + p [ i ] ∗ j dp[i-1][k]-p[i]*k+p[i]*j dp[i1][k]p[i]k+p[i]j,我们按顺序枚举时 p [ i ] ∗ j p[i]* j p[i]j已经确定,所以我们要求前面最大就行了(单调队列优化)
code:

#include<iostream>
#include<algorithm>
#include<deque>
#include<cstdio>
using namespace std;
int n,k,dp[110][16010];
struct f{
    
    
 int l,p,s;
} p[110];
bool cmp(f a,f b)
{
    
    
 return a.s<b.s;
}
deque<int> op[110];
int main()
{
    
    
 scanf("%d%d",&n,&k);
 for (int i=1;i<=k;i++) scanf("%d%d%d",&p[i].l,&p[i].p,&p[i].s);
 sort(p+1,p+k+1,cmp);
 for (int i=1;i<=k;i++)
 {
    
    
  op[i].push_back(max(0,p[i].s-p[i].l));
  for (int j=1;j<=n;j++)
  {
    
    
   dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
   if (j>=p[i].l+p[i].s) continue;
   while (!op[i].empty()&&op[i].front()+p[i].l<j) op[i].pop_front();
   if (j<p[i].s)
   {
    
    
    while (!op[i].empty()&&dp[i-1][op[i].back()]-op[i].back()*p[i].p<dp[i-1][j]-j*p[i].p) op[i].pop_back();
    op[i].push_back(j);
    continue; 
   }
   dp[i][j]=max(dp[i][j],dp[i-1][op[i].front()]+p[i].p*(j-op[i].front()));
  }
 }
 printf("%d",dp[k][n]);
 return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_49843717/article/details/114372213