Codeforces 677E Vanya and Balloons【断点前缀和+暴力维护+数学技巧】

E. Vanya and Balloons
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Vanya plays a game of balloons on the field of size n × n, where each cell contains a balloon with one of the values 0, 1, 2 or 3. The goal is to destroy a cross, such that the product of all values of balloons in the cross is maximum possible. There are two types of crosses: normal and rotated. For example:

**o**
**o**
ooooo
**o**
**o**

or

o***o
*o*o*
**o**
*o*o*
o***o

Formally, the cross is given by three integers r, c and d, such that d ≤ r, c ≤ n - d + 1. The normal cross consists of balloons located in cells (x, y) (where x stay for the number of the row and y for the number of the column), such that |x - r|·|y - c| = 0 and |x - r| + |y - c| < d. Rotated cross consists of balloons located in cells (x, y), such that |x - r| = |y - c| and |x - r| < d.

Vanya wants to know the maximum possible product of the values of balls forming one cross. As this value can be large, output it modulo 109 + 7.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 1000) — the number of rows and columns in the table with balloons.

The each of the following n lines contains n characters '0', '1', '2' or '3' — the description of the values in balloons.

Output

Print the maximum possible product modulo 109 + 7. Note, that you are not asked to maximize the remainder modulo 109 + 7, but to find the maximum value and print it this modulo.

Examples
Input
4
1233
0213
2020
0303
Output
108
Input
5
00300
00300
33333
00300
00300
Output
19683
Input
5
00003
02030
00300
03020
30000
Output
108
Input
5
21312
10003
10002
10003
23231
Output
3
Input
5
12131
12111
12112
21311
21212
Output
24
Note

In the first sample, the maximum product is achieved for a rotated cross with a center in the cell (3, 3) and radius 1: 2·2·3·3·3 = 108.


题目大意:

让你选择一个位子作为中心,向上下左右发散或者向左上左下右上右下发散。要求发散长度相同,将发散到的区域和中心的数字相乘,问最大的值%1e9+7是多少。


思路:


1、首先,他要的值不是%后最大值,而是最大值%1e9+7的值。

那么我们首先将乘变成加,对于123取对数来统计值。


2、我们O(n^2)维护一个前缀和,L【i】【j】表示以(i,j)这个点作为中心,向左发散的最大值(其实就是向左发散最长长度没有遇到0的值相乘)。

同时维护一个lenL【i】【j】,表示最大值发散的长度。

同理,我们需要维护八对这样的数组。

在我们遇到了数字0的时候,要对前缀和进行断点。


3、然后我们O(n^2)暴力枚举一个中心,对两种发散方式进行统计,看看哪个值更大,对于过程维护最大值的位子(posx,posy)以及一个发散长度,然后在最后维护最终解即可。


Ac代码(长到辣眼睛   ....):

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<cmath>
#include<iostream>
using namespace std;
#define ll __int64
#define mod 1000000007
int n;
char a[1005][1005];
int lenL[1005][1005];
int lenR[1005][1005];
int lenU[1005][1005];
int lenD[1005][1005];
int lenLU[1005][1005];
int lenRU[1005][1005];
int lenLD[1005][1005];
int lenRD[1005][1005];
double L[1005][1005];
double R[1005][1005];
double U[1005][1005];
double D[1005][1005];
double LU[1005][1005];
double RU[1005][1005];
double LD[1005][1005];
double RD[1005][1005];
int fx[8]={0,0,1,-1,1,-1,1,-1};
int fy[8]={1,-1,0,0,1,-1,-1,1};
double getval(int i,int j)
{
    if(a[i][j]=='0'||a[i][j]=='1')return 0;
    if(a[i][j]=='2')return log(2);
    if(a[i][j]=='3')return log(3);
}
void init()
{
    memset(lenLU,0,sizeof(lenLU));
    memset(lenRU,0,sizeof(lenRU));
    memset(lenLD,0,sizeof(lenLD));
    memset(lenRD,0,sizeof(lenRD));
    memset(lenL,0,sizeof(lenL));
    memset(lenR,0,sizeof(lenR));
    memset(lenU,0,sizeof(lenU));
    memset(lenD,0,sizeof(lenD));
    memset(L,0,sizeof(L));
    memset(R,0,sizeof(L));
    memset(U,0,sizeof(L));
    memset(D,0,sizeof(L));
    memset(LU,0,sizeof(LU));
    memset(RU,0,sizeof(RU));
    memset(LD,0,sizeof(LD));
    memset(RD,0,sizeof(RD));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
            {
                lenL[i][j]=0;
                L[i][j]=0;
            }
            else
            {
                lenL[i][j]=lenL[i][j-1]+1;
                L[i][j]=L[i][j-1]+getval(i,j);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=n;j>=1;j--)
        {
            if(a[i][j]=='0')
            {
                lenR[i][j]=0;
                R[i][j]=0;
            }
            else
            {
                lenR[i][j]=lenR[i][j+1]+1;
                R[i][j]=R[i][j+1]+getval(i,j);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
            {
                lenU[i][j]=0;
                U[i][j]=0;
            }
            else
            {
                lenU[i][j]=lenU[i-1][j]+1;
                U[i][j]=U[i-1][j]+getval(i,j);
            }
        }
    }
    for(int i=n;i>=1;i--)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
            {
                lenD[i][j]=0;
                D[i][j]=0;
            }
            else
            {
                lenD[i][j]=lenD[i+1][j]+1;
                D[i][j]=D[i+1][j]+getval(i,j);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
            {
                LU[i][j]=0;
                lenLU[i][j]=0;
            }
            else
            {
                lenLU[i][j]=lenLU[i-1][j-1]+1;
                LU[i][j]=LU[i-1][j-1]+getval(i,j);
            }
        }
    }
    for(int i=n;i>=1;i--)
    {
        for(int j=n;j>=1;j--)
        {
            if(a[i][j]=='0')
            {
                RD[i][j]=0;
                lenRD[i][j]=0;
            }
            else
            {
                lenRD[i][j]=lenRD[i+1][j+1]+1;
                RD[i][j]=RD[i+1][j+1]+getval(i,j);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=n;j>=1;j--)
        {
            if(a[i][j]=='0')
            {
                RU[i][j]=0;
                lenRU[i][j]=0;
            }
            else
            {
                lenRU[i][j]=lenRU[i-1][j+1]+1;
                RU[i][j]=RU[i-1][j+1]+getval(i,j);
            }
        }
    }
    for(int i=n;i>=1;i--)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
            {
                LD[i][j]=0;
                lenLD[i][j]=0;
            }
            else
            {
                lenLD[i][j]=lenLD[i+1][j-1]+1;
                LD[i][j]=LD[i+1][j-1]+getval(i,j);
            }
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
        init();
        double maxn=0;
        int len=0;
        int posx=-1,posy=-1;
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(a[i][j]=='0')continue;
                int minn=0x3f3f3f3f;
                minn=min(lenL[i][j],minn);
                minn=min(lenR[i][j],minn);
                minn=min(lenU[i][j],minn);
                minn=min(lenD[i][j],minn);
                double tmp=0;
                tmp+=L[i][j]-L[i][j-minn];
                tmp+=R[i][j]-R[i][j+minn];
                tmp+=U[i][j]-U[i-minn][j];
                tmp+=D[i][j]-D[i+minn][j];
                tmp-=3*getval(i,j);
                if(tmp>maxn)
                {
                    flag=1;
                    len=minn;
                    maxn=tmp;
                    posx=i,posy=j;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(a[i][j]=='0')continue;
                int minn=0x3f3f3f3f;
                minn=min(lenLU[i][j],minn);
                minn=min(lenRU[i][j],minn);
                minn=min(lenLD[i][j],minn);
                minn=min(lenRD[i][j],minn);
                double tmp=0;
                tmp+=LU[i][j]-LU[i-minn][j-minn];
                tmp+=RU[i][j]-RU[i-minn][j+minn];
                tmp+=LD[i][j]-LD[i+minn][j-minn];
                tmp+=RD[i][j]-RD[i+minn][j+minn];
                tmp-=3*getval(i,j);
                if(tmp>maxn)
                {
                    flag=2;
                    len=minn;
                    maxn=tmp;
                    posx=i,posy=j;
                }
            }
        }
        if(flag==0)
        {
            int output=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    output=max(a[i][j]-'0',output);
                }
            }
            printf("%d\n",output);
        }
        else if(flag==1)
        {
            ll output=(ll)a[posx][posy]-'0';
            for(int i=1;i<len;i++)
            {
                for(int k=0;k<4;k++)
                {
                    int xx=posx+i*fx[k];
                    int yy=posy+i*fy[k];
                    output*=(a[xx][yy]-'0');
                    output%=mod;
                }
            }
            printf("%I64d\n",output);
        }
        else
        {
            ll output=(ll)(a[posx][posy]-'0');
            for(int i=1;i<len;i++)
            {
                for(int k=4;k<8;k++)
                {
                    int xx=posx+i*fx[k];
                    int yy=posy+i*fy[k];
                    output*=(a[xx][yy]-'0');
                    output%=mod;
                }
            }
            printf("%I64d\n",output);
        }
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值