CodeForces 15D Map 单调队列优化

两次单调队列求出每个子矩阵的最小值,区间减法求出每个子矩阵的和,然后丢到优先队列里跑出来就好了。

写锉了,加了读入挂才过。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <ctime>
#include <iomanip>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-6)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 1000000007

/** I/O Accelerator Interface .. **/
#define g (c=getchar())
#define d isdigit(g)
#define p x=x*10+c-‘0‘
#define n x=x*10+‘0‘-c
#define pp l/=10,p
#define nn l/=10,n
template<class T> inline T& RD(T &x)
{
    char c;
    while(!d);
    x=c-‘0‘;
    while(d)p;
    return x;
}
template<class T> inline T& RDD(T &x)
{
    char c;
    while(g,c!=‘-‘&&!isdigit(c));
    if (c==‘-‘)
    {
        x=‘0‘-g;
        while(d)n;
    }
    else
    {
        x=c-‘0‘;
        while(d)p;
    }
    return x;
}
inline double& RF(double &x)      //scanf("%lf", &x);
{
    char c;
    while(g,c!=‘-‘&&c!=‘.‘&&!isdigit(c));
    if(c==‘-‘)if(g==‘.‘)
        {
            x=0;
            double l=1;
            while(d)nn;
            x*=l;
        }
        else
        {
            x=‘0‘-c;
            while(d)n;
            if(c==‘.‘)
            {
                double l=1;
                while(d)nn;
                x*=l;
            }
        }
    else if(c==‘.‘)
    {
        x=0;
        double l=1;
        while(d)pp;
        x*=l;
    }
    else
    {
        x=c-‘0‘;
        while(d)p;
        if(c==‘.‘)
        {
            double l=1;
            while(d)pp;
            x*=l;
        }
    }
    return x;
}
#undef nn
#undef pp
#undef n
#undef p
#undef d
#undef g
using namespace std;

const int BLOCK = sqrt(1000.0);

LL Map[1010][1010];

bool mark[1010][1010];

LL ans[1010][1010] = {0};

LL Min[1010][1010];

struct N
{
    int x,y;
    LL val;
    bool operator < (const N &a) const
    {
        if(val != a.val)
            return a.val < val;
        if(x != a.x)
            return a.x < x;
        return a.y < y;
    }
} tmp;

int x[1000100],y[1000100];
LL val[1000100];

priority_queue<N> q;

int que[1010];

void CalMin(int n,int m,int a,int b)
{
    int i,j,S,E;

    for(i = 1; i <= n; ++i)
    {
        S = 0,E = 0;
        for(j = m; j >= 1; --j)
        {
            while(E > S && Map[i][que[E-1]] > Map[i][j])
                E--;
            que[E++] = j;
            while(S < E && que[S] > j+b-1)
                S++;

            Min[i][j] = Map[i][que[S]];
        }
    }

    for(j = 1; j <= m; ++j)
    {
        S = 0,E = 0;
        for(i = n; i >= 1; --i)
        {
            while(E > S && Min[que[E-1]][j] > Min[i][j])
                E--;
            que[E++] = i;
            while(S < E && que[S] > i+a-1)
                S++;
            Map[i][j] = Min[que[S]][j];
        }
    }
}

int main()
{
    int i,j,n,m,a,b;
    RD(n);
    RD(m);
    RD(a);
    RD(b);
    // scanf("%d %d %d %d",&n,&m,&a,&b);

    for(i = 1; i <= n; ++i)
        for(j = 1; j <= m; ++j)
            RD(Map[i][j]);//scanf("%I64d",&Map[i][j]);

    for(i = n; i >= 1; --i)
        for(j = m; j >= 1; --j)
            ans[i][j] = Map[i][j] + ans[i+1][j] + ans[i][j+1] - ans[i+1][j+1];

    int N = n-a+1,M = m-b+1;

    for(i = 1; i <= N; ++i)
        for(j = 1; j <= M; ++j)
            ans[i][j] = ans[i][j] - ans[i+a][j] - ans[i][j+b] + ans[i+a][j+b];

    CalMin(n,m,a,b);

//    for(i = 1;i <= n; ++i)
//    {
//        for(j = 1;j <= m; ++j)
//            printf("%3I64d ",ans[i][j]);
//        puts("");
//    }
//
//    puts("");
//
//    for(i = 1;i <= n; ++i)
//    {
//        for(j = 1;j <= m; ++j)
//            printf("%3I64d ",Min[i][j]);
//        puts("");
//    }

    for(i = N; i >= 1; --i)
        for(j = M; j >= 1; --j)
            q.push( {i,j,ans[i][j]-Map[i][j]*a*b});
    memset(mark,false,sizeof(mark));

    int L,R,T,B,Top = 0;

    while(q.empty() == false)
    {
        tmp = q.top();
        q.pop();

        if(mark[tmp.x][tmp.y])
            continue;

        T = max(1,tmp.x-a+1),B = min(n,tmp.x+a-1);
        L = max(1,tmp.y-b+1),R = min(m,tmp.y+b-1);

        for(i = T; i <= B; ++i)
            for(j = L; j <= R; ++j)
                mark[i][j] = true;
        x[Top] = tmp.x,y[Top] = tmp.y,val[Top] = tmp.val,Top++;
    }

    printf("%d\n",Top);

    for(i = 0; i < Top; ++i)
        printf("%d %d %I64d\n",x[i],y[i],val[i]);

    return 0;
}
时间: 2024-11-10 18:01:52

CodeForces 15D Map 单调队列优化的相关文章

BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP

先建出广义后缀自动机. 然后跑出文章中每一个位置的最大匹配距离. 然后定义$f[i]$表示匹配到以$i$结尾的串时,最长的匹配距离. 显然可以二分$L$的取值. 然后容易得到$DP$方程 $f[i]=max(f[i-1],f[j]+i-j)(j<=i-L)$ 然后就发现$j$属于一个区间,然后就可以单调队列优化了. #include <map> #include <ctime> #include <cmath> #include <queue> #in

uvalive4327(单调队列优化)

这题我有闪过是用单调队列优化的想法,也想过有左右两边各烧一遍. 但是不敢确定,搜了题解,发现真的是用单调队列,然后写了好久,调了好久下标应该怎么变化才过的. dp[i][j] 表示走到第i行,第j个竖线的最大价值. dp[i][j] = max(dp[i-1][k]+pre[i][j-1]-pre[i][k-1]);  从左往右 dp[i][j] = max(dp[i][j],dp[i-1][k]+suf[i][j]-suf[i][k]); 从右往左 1 #pragma warning(disa

hdu 2191 (多重背包的单调队列优化)

多重背包单调队列优化是思想是.普通的dp为 dp[i][j]=max{dp[i-1][j-k*v[i]]+k*w[i]}; 其实你可以发现对能更新j是j和一个剩余类.也就是 0, v[i],2v[i],3v[i] ,4v[i]... 1 ,1+v[i],1+2v[i],1+3v[i] ........... v[i]-1,2*v[i]-1...... 更新值存在一个剩余类中,组与组之间不存在更新.那么实际上我们可以写dp写好这样 dp[b+x*v[i]]=max{ dp[b+k*v[i]]+(x

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

hdu3401 Trade(单调队列优化dp)

Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4734    Accepted Submission(s): 1587 Problem Description Recently, lxhgww is addicted to stock, he finds some regular patterns after a few d

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

woj 1575 - Signal generators 单调队列优化dp + 瞎搞

戳这里:1575 题意:直线上排列着N个信号发射器,每个信号发射器被激活后将会使得影响范围内的所有发射器都被激活.询问激活任意一个发射器后被激活的发射器数最大是多少. 官方题解:可能会存在环的情况,考虑按坐标排序后i < j < k,j激活了k,然后k再激活i.但是这样可以转化为直接激活k的方案.所以无影响. 于是可以用dp求解.dp[i] = max( dp[j] + 1 ), position[j] + R[i] >= position[i],用单调队列优化时间复杂度为O(n). 向