一、感想
大半夜写题解啊喂!没有无敌激动的情感至于这样吗!至于吗至于吗!思路之前就看过,下午又复习了一遍题解,结果晚上敲起来就是十点改到一点停都停不下来啊喂!
写完起码一点半了。我还在俱乐部。明早六点多爬起来上算法实验课。别睡了算了,修仙。
哎,实现功底需要提高。
二、题意
找到乘积最大的“十字架”。十字架的形状如题目的图所示。乘积是十字架里每一个数相乘。当然不能暴力,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;
}