【NOIP2016提高A组五校联考4】square

题目

分析

首先,设\(f_{i,j}\)表示最大的以(i,j)为左下角的正方形的边长。
转移显然,\(f_{i,j}=\max(f_{i-1,j},f_{i,j-1},f_{i-1,j-1})+1\)
接着,再设\(g_{i,j,k,l}\)表示在以\((k,l)\)为左上角,\((k+2^i-1,l+2^j-1)\)为右下角的矩阵中,最大的f。
二维rmq就不讲了。
假设询问矩阵(x,y,x1,y1),
二分答案ans(想想为什么?)

用rmq看红色区域中的最大f值是否合法。
注意:出题人将输入调的太大了,要打读入优化。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=1002;
using namespace std;
int f[N][N],n,m,T,g[11][11][N][N],a[N][N],logn,logm;
int read(int &n)
{
    char ch=' ';
    int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-') w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar()) q=q*10+ch-48;n=q*w;
    return n;
}
int min2(int x,int y)
{
    if(x>y) x=y;
    return x;
}
int max2(int x,int y)
{
    if(x<y) x=y;
    return x;
}
int min1(int x,int y,int z)
{
    if(x>y) x=y;
    if(x>z) x=z;
    return x;
}
int max1(int x,int y,int z,int a)
{
    if(x<y) x=y;
    if(x<z) x=z;
    if(x<a) x=a;
    return x;
}
int pref()
{
    int i,j;
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            if(a[i][j])
                g[0][0][i][j]=f[i][j]=min1(f[i-1][j-1],f[i-1][j],f[i][j-1])+1;
}
int prermq()
{
    int i,j,k,l;
    for(i=0;i<=logn;i++)
    {

        for(j=0;j<=logm;j++)
        {
            if(j+i!=0)
            {
                int p=1<<(i-1);
                int q=1<<(j-1);
                for(k=1;k<=n;k++)
                    if(k+p<=n)
                    {
                        for(l=1;l<=m;l++)
                            if(l+q<=m)
                            {
                                if(i!=0 && j!=0)
                                    g[i][j][k][l]=max1(g[i-1][j-1][k][l],g[i-1][j-1][k+p][l],g[i-1][j-1][k+p][l+q],g[i-1][j-1][k][l+q]);
                                else
                                if(i==0)
                                    g[i][j][k][l]=max2(g[i][j-1][k][l],g[i][j-1][k][l+q]);
                                else
                                if(j==0)
                                    g[i][j][k][l]=max2(g[i-1][j][k][l],g[i-1][j][k+p][l]);
                            }
                            else break;
                    }
                    else break;
            }
        }
    }
}
int rmq(int x,int y,int x1,int y1)
{
    int p=log2(x1-x+1),q=log2(y1-y+1);
    return max1(g[p][q][x][y],g[p][q][x1-(1<<p)+1][y],g[p][q][x][y1-(1<<q)+1],g[p][q][x1-(1<<p)+1][y1-(1<<q)+1]);
}
int rf(int x,int y,int x1,int y1)
{
    int lx=x1-x+1,ly=y1-y+1,l=1,r=min2(lx,ly);
    while(l<r-1)
    {
        int mid=(l+r)/2;
        if(rmq(x+mid-1,y+mid-1,x1,y1)>=mid)
            l=mid;
        else
            r=mid-1;
    }
    if(rmq(x+r-1,y+r-1,x1,y1)>=r)
        printf("%d\n",r);
    else
    if(rmq(x+l-1,y+l-1,x1,y1)>=l)
        printf("%d\n",l);
    else
        printf("0\n");
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            read(a[i][j]);
            f[i][j]=a[i][j];
        }
    pref();
    logn=log2(n);
    logm=log2(m);
    prermq();
    scanf("%d",&T);
    int x1,x2,y1,y2;
    for(int i=1;i<=T;i++)
    {
        read(x1);
        read(y1);
        read(x2);
        read(y2);
        rf(x1,y1,x2,y2);
    }
}

原文地址:https://www.cnblogs.com/chen1352/p/9065058.html

时间: 2024-10-18 00:39:16

【NOIP2016提高A组五校联考4】square的相关文章

【NOIP2016提高A组五校联考4】label

题目 题目 20%算法 设\(f_{i,j}\)表示第i个节点选了j这个权值的方案数. 显然转移方程为,\[f_{i,j}=\Pi_{v=son(i)}(\sum_{k=1}^{j-k}f_{v,k}+\sum_{k=j+k}^{m}f_{v,k})\] 40%算法 接着上面的想法, 观察转移方程,发现,求和部分其实是两段连续的,那么将\(f_{i}\)求一个前缀和. 100%算法 观察\(f\)数组,发现其实\(f\)是对称的,而且中间的一段是相同的,设深度为x,那么前面就有\((x-1)k\

【NOIP2016提高A组五校联考4】ksum

题目 分析 发现,当子段[l,r]被取了出来,那么[l-1,r].[l,r+1]一定也被取了出来. 那么,首先将[1,n]放入大顶堆,每次将堆顶的子段[l,r]取出来,因为它是堆顶,所以一定是最大的子段,输出它,并将[l+1,r]和[l,r-1]放进堆中. 一共就只用做k次就可以了. #include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <c

NOIP2016提高A组五校联考4总结

坑爹的第一题,我居然想了足足3个小时,而且还不确定是否正确. 于是,我就在这种情况下心惊胆跳的打了,好在ac了,否则就爆零了. 第二题,树形dp,本来差点就想到了正解,结果时间不够,没打完. 第三题,比赛上直接弃疗. 感想 首先强烈谴责出题人,输入开了10^6,我打了读入优化还调了半天才过,什么坑爹的题啊! 本来第一题是个水题,但是我却想了那么久,可能是因为我的基础打得不够扎实,基础训练不够,光顾着学习更高深的算法却忽略的基础的知识. 原文地址:https://www.cnblogs.com/c

五校联考 running (欧拉函数)

题面 \(solution:\) 讲真吧,这道题真的出得,嗯,太恐怖了.考场上这道题真的把我看懵了,这道题以前是见过的,但欧拉函数?我学过吗?一道容斥都要超时的题目,我都要为我自己点根香了,拿着gcd一顿乱搞,果然搞出了个0分.不得不承认博主的数学真的太渣了,但这道题的解题思路真的太妙了(因为渣所以必须学习!). 首先,一个必须要知道的东西,操场是环形的(即 \((mod\) \(n)\) 意义下的).若第\(k\)个格子可以被第\(i\)个同学踩到,那么必定存在一个\(x\) 使\(x*a_i

10.29 FJ四校联考

//四校联考Rank 16 感觉很滋磁 (虽然考的时候抱怨厦门一中出的数学题很NOIP///) 圈地 [问题描述] n根长度不一定相同的木棍,至多可以对其中一根切一刀,然后用其中的任意根围一个三角形,求三角形的最大面积.设面积为S,输出16*S^2对998244353取模后的答案.特别地,无解输出-1. 注:退化的三角形(面积为零)不被认为是三角形,答案应该为-1. [输入文件] 输入文件为tri.in. 输入文件第一行包含两个正整数n和998244353. 第二行包含n个正整数,表示每根木棍的

【NOIP2016提高A组模拟8.17】(雅礼联考day1)Binary

题目 分析 首先每个数对\(2^i\)取模.也就是把每个数的第i位以后删去. 把它们放进树状数组里面. 那么当查询操作, 答案就位于区间\([2^i-x,2^{i-1}-1-x]\)中,直接查询就可以了. 细节很多,注意处理. #include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algor

【NOIP2016提高A组模拟8.17】(雅礼联考day1)Value

题目 分析 易证,最优的答案一定是按\(w_i\)从小到大放. 我们考虑dp, 先将w从小到大排个序,再设\(f_{i,j}\)表示当前做到第i个物品,已选择了j个物品的最大值.转移就是\[f_{i,j}=max\left\{\begin{array}\\f_{i-1,j}\\f_{i-1,j-1}+v_i-w_i*(共选多少个物品(这个要枚举)-j)\end{array}\right.\] 但显然这是\(O(n^3)\)的. 我们考虑如何不用枚举共选多少个物品, 我们考虑反过来做,将w从大到小

八校联考第一场(20170917)

排列(permutation)题目描述]给定一个n*n 的矩阵f,你需要求出有多少个1~n 的排列x 满足对于1<=i≠j<=n,均有f[i,j]=min(x[i],x[j]),并输出字典序最小的一个.有多组数据.[输入数据]第一行一个整数t 表示数据组数.每组数据第一行一个正整数n.接下来n 行每行n 个整数,第i行第j 列的整数表示f[i,j].[输出数据]对于每组数据,如果不存在这样的排列,输出一行一个整数-1.否则输出两行,第一行一个整数表示排列个数对998244353 取模的结果,第

九校联考 终&amp;启

one term's ending... class:12 school:130...130...130... 至今没有看到九校的排名,如果九校排名正常的话,那yyhs的学生也太可怕了...估计要三百开外了 语文是比较意外的分数,尽管选择题做得差,可是有史以来第一次下110....why 数学和英语都比预估的低. 政史地84 65 78,感觉最对不起历史老师...地理从来没好过. 物化技82 75 83,是时候改课了..... 明明下半学期一直在学文化课...现在连浙大线都考不上了.... 学考