ОК, еще один дубль. Большая часть «мяса» находится в функции go
. Он использует ту же концепцию «расщепления», что и в моем другом ответе, но использует нисходящее динамическое программирование c с запоминанием. rmq2d
реализует 2D Range Minimum Query. для размера 1000x1000 это занимает около 30 секунд (при использовании 3 ГБ памяти).
#include <iostream>
#include <vector>
#include <cassert>
#include <set>
#include <tuple>
#include <memory.h>
#include <limits.h>
using namespace std;
constexpr int ilog2(int x){
return 31 - __builtin_clz(x);
}
const int MAX_DIM = 100;
template<class T>
struct rmq2d{
struct point{
int x,y;
point():x(0),y(0){}
point(int x,int y):x(x),y(y){}
};
typedef point array_t[MAX_DIM][ilog2(MAX_DIM)+1][MAX_DIM];
int h, logh;
int w, logw;
vector<vector<T>> v;
array_t *A;
rmq2d(){A=nullptr;}
rmq2d &operator=(const rmq2d &other){
assert(sizeof(point)==8);
if(this == &other) return *this;
if(!A){
A = new array_t[ilog2(MAX_DIM)+1];
}
v=other.v;
h=other.h;
logh = other.logh;
w=other.w;
logw=other.logw;
memcpy(A, other.A, (ilog2(MAX_DIM)+1)*sizeof(array_t));
return *this;
}
rmq2d(const rmq2d &other){
A = nullptr;
*this = other;
}
~rmq2d(){
delete[] A;
}
T query(point pos){
return v[pos.y][pos.x];
}
rmq2d(vector<vector<T>> &v) : v(v){
A = new array_t[ilog2(MAX_DIM)+1];
h = (int)v.size();
logh = ilog2(h) + 1;
w = (int)v[0].size();
logw = ilog2(w) + 1;
for(int y=0; y<h; ++y){
for(int x=0;x<w;x++) A[0][y][0][x] = {x, y};
for(int jx=1; jx<logw; jx++){
int sz = 1<<(jx-1);
for(int x=0; x+sz < w; x++){
point i1 = A[0][y][jx-1][x];
point i2 = A[0][y][jx-1][x+sz];
if(query(i1) < query(i2)){
A[0][y][jx][x] = i1;
}else{
A[0][y][jx][x] = i2;
}
}
}
}
for(int jy=1; jy<logh; ++jy){
int sz = 1<<(jy-1);
for(int y=0; y+sz<h; ++y){
for(int jx=0; jx<logw; ++jx){
for(int x=0; x<w; ++x){
point i1 = A[jy-1][y][jx][x];
point i2 = A[jy-1][y+sz][jx][x];
if(query(i1) < query(i2)){
A[jy][y][jx][x] = i1;
}else{
A[jy][y][jx][x] = i2;
}
}
}
}
}
}
point pos_q(int x1, int x2, int y1, int y2){
assert(A);
int lenx = ilog2(x2 - x1);
int leny = ilog2(y2 - y1);
point idxs[] = {
A[leny][y1][lenx][x1],
A[leny][y2-(1<<leny)][lenx][x1],
A[leny][y1][lenx][x2-(1<<lenx)],
A[leny][y2-(1<<leny)][lenx][x2-(1<<lenx)]
};
point ret = idxs[0];
for(int i=1; i<4; ++i){
if(query(ret) > query(idxs[i])) ret = idxs[i];
}
return ret;
}
T val_q(int x1, int x2, int y1, int y2){
point pos = pos_q(x1,x2,y1,y2);
return v[pos.y][pos.x];
}
};
rmq2d<long long> rmq;
set<tuple<int, int, int ,int>> cac;
vector<vector<long long>> v(MAX_DIM-5,vector<long long>(MAX_DIM-5,0));
long long ret = 0;
int nq = 0;
void go(int x1, int x2, int y1, int y2){
if(x1 >= x2 || y1>=y2) return;
if(!cac.insert(make_tuple(x1,y1,x2,y2)).second) return;
++nq;
auto p = rmq.pos_q(x1, x2, y1, y2);
long long cur = v[p.y][p.x]*(x2-x1)*(y2-y1);
if(cur > ret){
cout << x1 << "-" << x2 << ", " << y1 << "-" << y2 << " h=" << v[p.y][p.x] << " :" << cur << endl;
ret = cur;
}
go(p.x+1, x2, y1, y2);
go(x1, p.x, y1, y2);
go(x1, x2, p.y+1, y2);
go(x1, x2, y1, p.y);
}
int main(){
int W = (int)v[0].size();
int H=(int)v.size();
for(int y=0; y<H;++y){
for(int x=0; x<W; ++x){
v[y][x] = rand()%10000;
}
}
rmq = rmq2d<long long>(v);
go(0,W, 0, H);
cout << "nq:" << nq << endl;
}