hdu_4374 One hundred layer解题报告

第一次写单调队列优化的dp。。

解题思路:dp很明显了,和上次多校的一道题差不多。(dragon ball)

可以看成是分组的背包问题(背包九讲06)每一层是一组,不过不能不取。

但是这样,dp[i][p]--第i层第p个位置可以取到的最大值。直接递推复杂度O(n*m*T*2)

肯定不行。于是用单调队列:假设dp[i][p]只和第i+1层p左边的最优值有关。这样的话左-〉右推过去每层可以基本O(M)的推出dp值,可是题目是和两边都有关啊。。。再从右面推到左面。和原来存在dp[i][p]内的值比较去最优即可。

我自己写的单调队列类,实际证明还是起了作用的。

我的代码差。。怎么也优化不到200ms。。唉





#include"stdio.h"
#include"stdlib.h"
#include"time.h"
#include"math.h"
#include"iostream"
#include"string.h"
#include"algorithm"

#define nmax 110
#define mmax 10010
#define inf 6000000

inline int maxy(int a,int b){return a>b?a:b;}
inline int miny(int a,int b){return a<b?a:b;}
inline long long  maxy(long long  a,long long  b){return a>b?a:b;}
inline long long  miny(long long  a,long long  b){return a<b?a:b;}
using namespace std;

int N,M,X,T;
int mat[nmax][mmax];
int sum[nmax][mmax];

int dp[nmax][mmax];
//bool vis[nmax][mmax];

///-------------
class Que{
    //private:
    //int head,tail;
    public:
    int A,B;
    int q[mmax];
    int ind[mmax];
    public:
    void init();
    void add2right(int v,int i);
    void add2right_min(int v,int i);
    void pop();
    int leftmosti();
    int front();
    int size();
}q1;

///func
int Que::size(){
    return B-A;
}
void Que::init(){
    A=B=0;
}
void Que::add2right(int v,int i){
    //int &A=head;
    //int &B=tail;
    if(A==B){
        ind[B]=i;
        q[B++]=v;
    }
    else {
        //!empty
        while(B!=A){
            if(q[B-1]<v){
                B--;
            }
            else {break;}
        }
        ind[B]=i;
        q[B++]=v;
    }
}
void Que::add2right_min(int v,int i){
    if(A==B){
        ind[B]=i;
        q[B++]=v;
    }
    else {
        //!empty
        while(B!=A){
            if(q[B-1]>v){
                B--;
            }
            else {break;}
        }
        ind[B]=i;
        q[B++]=v;
    }
}
void Que::pop(){
    A++;
}
int Que::leftmosti(){
    if(A==B)return -1;
    return ind[A];
}
int Que::front(){
    if(A==B)return -1;
    return q[A];
}
///----------------

int get_sum(int fl,int st,int ed){
    if(st==ed)return mat[fl][st];
    if(st>ed){
        return sum[fl][st]-sum[fl][ed-1];
    }
	else{
        return sum[fl][ed]-sum[fl][st-1];
    }
}

int main(){

    while(scanf("%d%d%d%d",&N,&M,&X,&T)==4){
        int i;

        for(i=1;i<=N;i++){
            mat[i][0]=mat[i][N+1]=0;
            sum[i][0]=0;
            for(int j=1;j<=M;j++){
                scanf("%d",&mat[i][j]);
                sum[i][j]=mat[i][j]+sum[i][j-1];

            }
        }//io

        for(i=0;i<=M;i++)dp[N+1][i]=0;

        for(i=N;i>=1;i--){
            int j;
            //left to right;
            int cursum=get_sum(i,1,M);
            q1.init();
            for(j=1;j<=M;j++){

                while(q1.size()>0&&abs(j-q1.leftmosti())>T)q1.pop();
                cursum-=mat[i][j-1];
                q1.add2right(cursum+dp[i+1][j],j);

                int con=0;
                if(j<M)con=get_sum(i,j+1,M);
                dp[i][j]=q1.front()-con;
            }
			///2nd-------------
            cursum=get_sum(i,1,M);
            q1.init();
            for(j=M;j>0;j--){

                while(q1.size()>0&&abs(j-q1.leftmosti())>T)q1.pop();
                cursum-=mat[i][j+1];

                q1.add2right(cursum+dp[i+1][j],j);

                int con=0;
                if(j>1)con=get_sum(i,j-1,1);
                dp[i][j]=maxy(dp[i][j],q1.front()-con);
            }
        }
        printf("%d\n",dp[1][X]);
    }

return 0;}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值