hdu 5749 公式

題目鏈接: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;
}


發佈了36 篇原創文章 · 獲贊 1 · 訪問量 7745
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章