題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5749
參考文章:http://m.blog.csdn.net/article/details?id=52020617
題目要求求出這個公式的值,首先來看S(a,b),其實對於一個矩陣,可以手動畫一下,一個矩陣的鞍點至多隻有一個,那麼s(a,b)其實就是矩陣中這個鞍點的值,那麼如何來求鞍點。
如果一個點能成爲某個矩陣的鞍點,按題目所說,那麼這個點的左右的點都比這個點大,上下的點都比這個點小,那麼對於一個點就是要求出最長這個點可以把四個邊延長多長,u,d,l,r。用單調棧的處理可以快一點,不知道暴力處理能不能過。
處理出來好後,因爲一個矩陣最多隻有一個這樣的鞍點,那麼,就是枚舉每個點,它能成爲多少個矩陣的鞍點,因爲已經知道一個點作爲鞍點所能構成的最大矩陣,那麼在這個矩陣內部且包含該點的都是滿足條件的矩陣。然後原來的公式呢其實就是枚舉每一個這樣的矩陣加起來。具體化解可以看這裏http://m.blog.csdn.net/article/details?id=52020617
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define LL long long
LL u[1005][1005];
LL d[1005][1005];
LL l[1005][1005];
LL r[1005][1005];
LL dat[1005][1005];
int n,m;
void Left()
{
for(int i = 0;i<n;i++)
{
stack<pair<int,int> >sta;
for(int j = 0;j<m;j++)
{
if(sta.empty())
{
pair<int,int> temp;
temp.first = dat[i][j];
temp.second = j;
sta.push(temp);
l[i][j] = 1;
}
else
{
while(!sta.empty() && sta.top().first>dat[i][j])
{
sta.pop();
}
if(sta.empty())
{
l[i][j] = j+1;
}
else
l[i][j] = j-sta.top().second;
pair<int,int>temp;
temp.first = dat[i][j];
temp.second = j;
sta.push(temp);
}
}
}
}
void Right()
{
for(int i = 0;i<n;i++)
{
stack<pair<int,int> >sta;
for(int j = m-1;j>=0;j--)
{
if(sta.empty())
{
pair<int,int> temp;
temp.first = dat[i][j];
temp.second = j;
sta.push(temp);
r[i][j] = 1;
}
else
{
while(!sta.empty() && sta.top().first>dat[i][j] )
{
sta.pop();
}
pair<int,int>temp;
if(sta.empty())
r[i][j] = m-j;
else
r[i][j] = sta.top().second-j;
temp.first = dat[i][j];
temp.second = j;
sta.push(temp);
}
}
}
}
void UP()
{
for(int j = 0;j<m;j++)
{
stack<pair<int,int> >sta;
for(int i = 0;i<n;i++)
{
if(sta.empty())
{
pair<int,int> temp;
temp.first = dat[i][j];
temp.second = i;
sta.push(temp);
u[i][j] = 1;
}
else
{
//cout << "666";
while(!sta.empty() && sta.top().first<dat[i][j] )
{
sta.pop();
}
if(sta.empty())
{
u[i][j] = i+1;
}
else
u[i][j] = i-sta.top().second;
pair<int ,int> temp;
temp.first = dat[i][j];
temp.second = i;
sta.push(temp);
}
}
}
}
void Down()
{
for(int j = 0;j<m;j++)
{
stack<pair<int,int> >sta;
for(int i = n-1;i>=0;i--)
{
if(sta.empty())
{
pair<int,int> temp;
temp.first = dat[i][j];
temp.second = i;
sta.push(temp);
d[i][j] = 1;
}
else
{
while(!sta.empty() && sta.top().first<dat[i][j])
{
sta.pop();
}
if(sta.empty())
{
d[i][j] = n-i;
}
else
d[i][j] = sta.top().second-i;
pair<int ,int> temp;
temp.first = dat[i][j];
temp.second = i;
sta.push(temp);
}
}
}
}
void Print(LL arr[][1005])
{
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
printf("%4lld",arr[i][j]);
}
printf("\n");
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
scanf("%lld",&dat[i][j]);
}
}
// 左邊界
Left();
Right();//printf("123");
UP();
Down();
LL ans = 0;
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
LL temp = (l[i][j]*r[i][j]*u[i][j]*d[i][j])*(l[i][j]+r[i][j])*(u[i][j]+d[i][j]);
temp *= dat[i][j];
temp /= 4;
temp %= (1ll<<32);
ans += temp;
ans %= (1ll<<32);
}
}
printf("%lld\n",ans);
}
return 0;
}