Fの植樹
トピックリンク
https://ac.nowcoder.com/acm/contest/883/F
タイトル説明
学期がついに終わり、夏休みが来ています。しかし、あなたの大学の卒業要件の一部として、あなたは休日の間に、いくつかの社会的なサービスに参加する必要があります。結局、あなたは山で木を植えるボランティアグループに参加することを決めました。
問題を単純化するために、木が植えられたことがある場所の山を表現してみましょう\(N \ N回\)グリッド。レッツ数行\(\ 1 \)がします(\ N \)を\上から下へ、そして数が列\(\ 1 \)がする(\ N \)\左から右へ。細胞の上昇(\ \ iは\)行目及び(\ \ J \)列目はで表される(\ A_ {I、J})\。あなたのリーダーは、木が山の中に、その矩形内のセル間の高低差の最大値は、換言すれば、Mを超えてはならないことを矩形領域に植えされるべきであると決定した場合、左上と右下の座標矩形の角部である\((X_1、Y_1)\)と\((X_2、Y_2)\) 、次に条件$ | A_ {I、J} - A_ {K、L} | \ルM $のために保持する必要があります\(X_1 \ルI、kは\ルX_2、\ Y_1 \ルJ、L \ルY_2 \) 。彼が植えされますどのように多くの木々がわかりますように、あなたの指導者がこのような長方形のセルの最大数を計算する助けてください。
説明を入力します。
入力は複数の例が含まれています。入力の最初の行は、単一の整数含ま\(T \(1 \ルT \ル1000)\) 、ケースの数を。
各場合について、入力の最初の行は、2つの整数$ Nを含有する(1 \ルN \ル500)$および\(M \(0 \ルM \ル10 ^ 5)\) 。ここで、次のN行はそれぞれ、N個の整数を含む\(\ j番目の\) I I i番目の行の整数を表し、\(A_ {I、J} \(1 \ルA_ル{I、J} \ 10 ^ 5)\) 。
の合計ことが保証されている\(\ N ^ 3)すべてのケースの上には超えていない\(25 \ CDOT 10 ^ 7 \)を。
出力説明:
それぞれの場合のために、単一の整数、有効な矩形のセルの最大数を印刷します。
エントリー
2
2 0
1 2
2 1
3 1
1 3 2
2 3 1
3 2 1
輸出
1
4
問題の意味
あなたは与える\(N \ N回\)行列、自己探求最大とminimum'reを満たすほとんどの部分行列の行列mよりだけ少ないです。
問題の解決策
最後の文でまともな外観は、その疑問に思いました\(N ^ 3 \)考えるのが自然であるので、アルゴリズムを\(^ 2 \ n)を列挙し、前の下限は、\(N \)を再度スキャンします。
私たちは上限と下限を決めると考えられる場合は、その後、我々はできるだけ長く、左の境界、右の境界を列挙しますが、確かではないがしたいときは、右の時間の左端に、右の境界は、困難な希望があってはならない(左になりません)を考えるのは難しい、これは定規エミュレートと呼ばれているように見えます。
残りは要件の最小値と最大値の範囲である、と私は二重の二次元を指示するために始めた、タイムアウトの結果は、唯一あきらめて、2時間以上の残業を変更しました。最小値と最大値を求めるために、キューの単調さが続く、このアプローチは非常に古典的な感じが、私はそれを参照するか、いくつかのトピックをしませんでした。
簡単に言えば単調キューを語ります:
我々は2つのキュー、最大値を選択するための1つ、他のに必要な最低限に従事します
最初のステップ:キューの違法ヘッドを取り外します(左マージンを変更)
パートII:右の境界線を遡っ
パートIII:更新の回答
基本的な問題を終え、これも自然になりますので、少し抽象的な話をした後、私はタイトルの基礎を見つけるために行ってきました。
ACコード
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x7f7f7f7f
#define N 505
#define maxx(a,b) a<b?b:a
#define minn(a,b) a<b?a:b
int n,m,mx[N],mi[N],a[N][N];
struct Queue{int val,id;}Q1[N],Q2[N];
clock_t now;
template<typename T>void read(T&x)
{
ll k=0; char c=getchar();
x=0;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit(0);
while(isdigit(c))x=x*10+c-'0',c=getchar();
x=k?-x:x;
}
inline void work()
{
now=clock();
int ans=1;
read(n); read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
read(a[i][j]);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int ds1=1,dw1=0,ds2=1,dw2=0,r=0;
for(int k=1;k<=n;k++)
{
if (i==j)mx[k]=mi[k]=a[i][k];
else {mx[k]=maxx(mx[k],a[j][k]);mi[k]=minn(mi[k],a[j][k]);}
}
for(int k=1;k<=n;k++)
{
r=maxx(r,k-1);
while(ds1<=dw1&&Q1[ds1].id<k)ds1++;
while(ds2<=dw2&&Q2[ds2].id<k)ds2++;
if (mx[k]-mi[k]>m)continue;
int m1=maxx(mx[r+1],Q1[ds1].val);
int m2=minn(mi[r+1],Q2[ds2].val);
if (ds1>dw1)m1=mx[r+1],m2=mi[r+1];
while(r+1<=n&&(mx[r+1]-mi[r+1]<=m)&&(ds1>dw1||m1-m2<=m))
{
while(mx[r+1]>Q1[dw1].val&&ds1<=dw1)dw1--;
while(mi[r+1]<Q2[dw2].val&&ds2<=dw2)dw2--;
Q1[++dw1]={mx[r+1],r+1};
Q2[++dw2]={mi[r+1],r+1};
r++;
m1=maxx(m1,mx[r+1]);
m2=minn(m2,mi[r+1]);
}
ans=maxx(ans,(j-i+1)*(r-k+1));
}
}
printf("%d\n",ans);
//cout<<(double)(clock()-now)/CLOCKS_PER_SEC*1000<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
int T;
read(T);
while(T--)work();
}
タイムアウトコード(のみ表示)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x7f7f7f7f
#define N 505
int n,m,mx[N][N][10][10],mi[N][N][10][10],mm[N],mv[10];
template<typename T>void read(T&x)
{
ll k=0; char c=getchar();
x=0;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit(0);
while(isdigit(c))x=x*10+c-'0',c=getchar();
x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
void build_ST()
{
for(int i=2;i<=n;i++)mm[i]=mm[i>>1]+1;
for(int i=0;i<=10;i++)mv[i]=1<<i;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mx[i][j][0][0]=mi[i][j][0][0];
for(int k=1;k<=8;k++)
for(int i=1;i<=n;i++)
for(int j=1;j+(1<<k)-1<=n;j++)
{
mx[i][j][0][k]=max(mx[i][j][0][k-1],mx[i][j+(1<<(k-1))][0][k-1]);
mi[i][j][0][k]=min(mi[i][j][0][k-1],mi[i][j+(1<<(k-1))][0][k-1]);
}
for(int k1=1;k1<=8;k1++)
for(int k2=0;k2<=8;k2++)
for(int i=1;i+(1<<k1)-1<=n;i++)
for(int j=1;j+(1<<k2)-1<=n;j++)
{
mx[i][j][k1][k2]=
max(mx[i][j][k1-1][k2],mx[i+(1<<(k1-1))][j][k1-1][k2]);
mi[i][j][k1][k2]=
min(mi[i][j][k1-1][k2],mi[i+(1<<(k1-1))][j][k1-1][k2]);
}
}
inline int get_mx(int x1,int y1,int x2,int y2)
{
int k1=mm[x2-x1+1],k2=mm[y2-y1+1];
x2=x2-mv[k1]+1;
y2=y2-mv[k2]+1;
int a1=max(mx[x1][y1][k1][k2],mx[x1][y2][k1][k2]);
int a2=max(mx[x2][y1][k1][k2],mx[x2][y2][k1][k2]);
return max(a1,a2);
}
inline int get_mi(int x1,int y1,int x2,int y2)
{
int k1=mm[x2-x1+1],k2=mm[y2-y1+1];
x2=x2-(1<<k1)+1;
y2=y2-(1<<k2)+1;
int a1=min(mi[x1][y1][k1][k2],mi[x1][y2][k1][k2]);
int a2=min(mi[x2][y1][k1][k2],mi[x2][y2][k1][k2]);
return min(a1,a2);
}
void work()
{
int ans=1;
read(n); read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
read(mi[i][j][0][0]);
build_ST();
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int l=1;
for(int k=1;k<=n;k++)
{
int mx=get_mx(i,l,j,k);
int mi=get_mi(i,l,j,k);
while(mx-mi>m&&l<=k)
{
l++;
if(l<=k)mx=get_mx(i,l,j,k);
if(l<=k)mi=get_mi(i,l,j,k);
}
ans=max(ans,(j-i+1)*(k-l+1));
}
}
printf("%d\n",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
int T;
read(T);
while(T--)work();
}