cf677E Vanya and Balloons (前缀和)

题目链接

一、感想

大半夜写题解啊喂!没有无敌激动的情感至于这样吗!至于吗至于吗!思路之前就看过,下午又复习了一遍题解,结果晚上敲起来就是十点改到一点停都停不下来啊喂!

写完起码一点半了。我还在俱乐部。明早六点多爬起来上算法实验课。别睡了算了,修仙。

哎,实现功底需要提高。

二、题意

找到乘积最大的“十字架”。十字架的形状如题目的图所示。乘积是十字架里每一个数相乘。当然不能暴力,n*n*m*m不是开玩笑的。但是可以用前缀和实现每个方向预处理、每个点O(1)找到最大十字架,最后扫一遍O(1)读出每个点的最大值即可。

处理八个方向的前缀和,是从每个方向的“尽头”开始处理,这个尽头不需要自己写公式找规律,把每个点跑一遍,然后按照当前这种方向往前退一位看看出界了没就行。

把乘积取对数转化成相加的方式,这一点很有用。

先扫一遍把每个位置对数全部读出来存在一个表里,这种操作极大方便了后面敲代码,而且只是扫一遍,也是预处理了。

基本用const int _n = 1e9 + 7,今天敲着敲着懒得拖到最顶上写个const,也思维定式不晓得直接在这里写const,抽筋了手动打了1000000009,结果好了,少打了一个0。以后不要再犯蠢了。
然后定义变量的时候,定义在全局会自动赋初值的,感觉大部分时候是0?自己写在里面也要定义初值。一发RE就是输入了1 0,然后变量没有赋初值,什么循环都没进去,输出来就是没有赋值过的答案,就RE了。也好,见识到了RE除了数组越界还有这花式RE方法。

扫描二维码关注公众号,回复: 6730870 查看本文章
#include<bits/stdc++.h>
using namespace std;
int dir[8][2] = {-1, -1, -1, 1, 1, -1, 1, 1,
0, 1, 0, -1, 1, 0, -1, 0};
const int mx = 1e3 + 5;
char a[mx][mx];
double logs[mx][mx];
int pre[8][mx][mx];
double sum[8][mx][mx];
int n;
bool in(int x){
    return x >= 0 && x < n;
}
void pre_work(){
    double lg2 = log(2), lg3 = log(3);
    for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++){
        if(a[i][j] == '2') logs[i][j] = lg2;
        if(a[i][j] == '3') logs[i][j] = lg3;
    }
    int k;//用来计数 看最多有几个可以伸展
    for(int di = 0; di < 8; di++){
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                int d1 = dir[di][0], d2 = dir[di][1];
                if(!in(i - d1) || !in(j - d2)){//预处理这个方向每个点非零数个数
                    //并预处理前缀和
                    k = 0;
                    int x = i, y = j;
                    while(in(x) && in(y)){
                        if(a[x][y] != '0'){
                            k++;
                            if(x == i && y == j)    sum[di][x][y] = logs[i][j];
                            else    sum[di][x][y] = sum[di][x-d1][y-d2] + logs[x][y];
                        }
                        else {
                            sum[di][x][y] = 0;
                            k = 0;
                        }
                        pre[di][x][y] = k;//这个k是包括自己在内的长度
                        x += d1, y += d2;
                    }
                }
            }
        }
    }
}
int main(){
    cin >> n;
    for(int i = 0; i < n; i++){
        scanf("%s", a[i]);
    }
    pre_work();
//    for(int i = 0; i < n; i++){
//    for(int j = 0; j < n; j++){
//        cout << pre[2][i][j] << "  ";
//    }
//    cout << '\n';
//    }
    int ansdir = 0;
    double val = 0;
    int fx = 0, fy = 0;
    int f_len = 0;
    for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++){//找到最大的十字架
        if(a[i][j] == '0') continue;
        int len = n + 1;
        for(int di = 0; di < 4; di++){
            len = min(len, pre[di][i][j]);
        }
//        cout << i << ' ' << j << ":" << len << endl;
        double s = logs[i][j];
        for(int k = 0; k < 4; k++){
            s += (sum[k][i + (len-1)*dir[k][0]][j + (len-1)*dir[k][1]] - sum[k][i][j]);//不用把自己加上
        }
//        cout << i << ' ' << j << ":" <<len <<' '<< s << endl;
        if(s > val){
            f_len = len;
            val = s;
            fx = i, fy = j;
            ansdir = 0;
        }
        len = n + 1;
        for(int di = 4; di < 8; di++){
            len = min(len, pre[di][i][j]);
        }
//        cout << i << ' ' << j << ":" << len << endl;
        s = logs[i][j];
        //s是以s为十字架中心能到的最大lg(乘积)
        for(int k = 4; k < 8; k++){
            s += (sum[k][i + (len-1)*dir[k][0]][j + (len - 1)*dir[k][1]] - sum[k][i][j]);//不用把自己加上
        }
//        cout << i << ' ' << j << ":" <<len <<' '<< s << endl;
        if(s > val){
            f_len = len;
            val = s;
            fx = i, fy = j;
            ansdir = 4;
        }
    }
    //val是前面的 val1是后面的
    int k = ansdir;
    long long ans = a[fx][fy] - '0';
    for(int di = k; di < 4 + k; di++){
        for(int i = 1; i < f_len; i++){
            ans *= a[fx + i * dir[di][0]][fy + i * dir[di][1]] - '0' ;
            ans %= 1000000007;
        }
    }
    cout << ans << endl;
    return 0;
}
 
 
 

猜你喜欢

转载自blog.csdn.net/xuzonghao/article/details/88730582