zoukankan      html  css  js  c++  java
  • 洛谷 P1736 创意吃鱼法(多维DP)

    题目描述

    回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*)。她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略。

    在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中。

    猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的鱼。请你帮猫猫计算一下,她一口下去,最多可以吃掉多少条鱼?

    输入输出格式

    输入格式:

    有多组输入数据,每组数据:

    第一行有两个整数n和m(n,m≥1),描述池塘规模。接下来的n行,每行有m个数字(非“0”即“1”)。每两个数字之间用空格隔开。

    对于30%的数据,有n,m≤100

    对于60%的数据,有n,m≤1000

    对于100%的数据,有n,m≤2500

    输出格式:

    只有一个整数——猫猫一口下去可以吃掉的鱼的数量,占一行,行末有回车。

    --------------------------------------------我是分割线------------------------------------------------

    这题我用的是N2logN的二分,还挺好写的,效率也很可观。

    进入正题:

    首先要对角线要分成两种,一种是/这样的,一种是这样的(灵魂题解~~),这是两个相似的问题,我们可以先解决一个,然后把代码复制一下(嘿嘿嘿)。

    我们来看一下这样的对角线,式子很明显:

    f[i][j]表示以(i,j)为终点的对角线长度,因此这里一定有要鱼

    如果矩阵(i-x,j-x,i,j)是满足题目要求的,那么f[i][j]=max(f[i][j],x)。

    同时我们发现,1.x越大越好。2.x的上界是f[i-1][j-1],因为超过这个一定不满足要求。3.如果x不满足要求,那么x到其上界就都不满足。

    似乎满足单调性?

    那么我们可以二分x。

    之后我们再来看满足题目要求的矩阵

    举个例子:

    1 0 0 0

    0 1 0 1

    0 0 1 0

    0 0 0 1

    当i=4,j=4时,由于我们之前算出来f[3][3]是三,那么矩阵(1,1,3,3)一定是符合要求的,所以我们只需要判断第i行1到j个元素与第j行1到i个元素有没有鱼就可以了。

    但如果暴力算的话会T,我们可以算矩阵(i-x,j-x,i,j)的和是不是x+1。于是就可以用到我们的二维前缀和了。

    贴一下代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    int f[2501][2501],s[2501][2501],i;
    int a[2501][2501],n,m,l,r,mid,ans,j;
    inline int read(){
        int x=0,p=1; char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch == '-') p=-1; ch=getchar();}
        while (ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
        return x*p;
    }
    int main(){
        n=read(); m=read();
        for (i=1; i<=n; i++)
            for (j=1; j<=m; j++){
                a[i][j]=read();
                s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
            }
        for (i=1; i<=n; i++)
            for (j=1; j<=m; j++){
                if (a[i][j]){
                  f[i][j]=1;
                  if (f[i-1][j-1]){
                    l=0; r=f[i-1][j-1];
                    while (l<=r){
                        mid=l+r>>1;
                        if (s[i][j]-s[i-mid-1][j]-s[i][j-mid-1]+s[i-mid-1][j-mid-1]==mid+1)
                           l=mid+1;
                        else r=mid-1;
                    }
                    f[i][j]=max(f[i][j],l);
                    }
                }
                ans=max(ans,f[i][j]);
            }
        memset(f,0,sizeof(f));
        for (i=1; i<=n; i++)
            for (j=m; j>=1; j--){
                if (a[i][j]){
                    f[i][j]=1;
                    l=0; r=f[i-1][j+1];
                    while (l<=r){
                        mid=l+r>>1;
                        if (s[i][j+mid]-s[i][j-1]-s[i-mid-1][j+mid]+s[i-mid-1][j-1]==mid+1)
                           l=mid+1;
                        else r=mid-1;
                    }
                    f[i][j]=max(f[i][j],l);
                }
                ans=max(ans,f[i][j]);
            }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Java实现 LeetCode 455 分发饼干
    Java实现 LeetCode 455 分发饼干
    Java实现 LeetCode 455 分发饼干
    Java实现 LeetCode 454 四数相加 II
    Java实现 LeetCode 454 四数相加 II
    Java实现 LeetCode 454 四数相加 II
    FFmpeg解码H264及swscale缩放详解
    linux中cat more less head tail 命令区别
    C语言字符串操作总结大全(超详细)
    如何使用eclipse进行嵌入式Linux的开发
  • 原文地址:https://www.cnblogs.com/taduro/p/9466107.html
Copyright © 2011-2022 走看看