bzoj1414

manacher+单调栈:

题解正在写。。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct mapp
{
	int value;
	int rline, rrow;//以此点为对称中心的对称串半径
	int r;//最后能得到的最大正方形半径
	int tr[5];//四个方向能得到的最大半径
	void getans()
	{
		int t1 = min(rline, rrow); int t2 = min(tr[1], tr[2]); int t3 = min(tr[3], tr[4]);
		r = min(t1, t2);
		r = min(r, t3);
	}
};
mapp t[2010][2010];//记录各点信息
int n, m;
struct roww//维护栈里的能影响那些点
{
	int pos, influence, realpos;
};
roww rst[3000];
struct linee
{
	int pos, influence, realpos;
};
linee lst[3000];
struct hh
{
	int h, pos;
};
hh height[3000];//维护栈里的各种长度
void getrow(int num)//横着一边manacher
{
	int circle = 1; int r = 1;
	t[num][1].rrow = 1;
	for (int i = 2; i <= 2 * m - 1; i++)
	{
		if (circle + r - 1 > i)
			t[num][i].rrow = min(circle + r - 1 - i + 1, t[num][2 * circle - i].rrow);
		else
			t[num][i].rrow = 1;
		while (i + t[num][i].rrow <= 2 * m - 1 && i - t[num][i].rrow >= 1 && t[num][i + t[num][i].rrow].value == t[num][i - t[num][i].rrow].value)
			t[num][i].rrow++;
		if (i + t[num][i].rrow > circle + r)circle = i, r = t[num][i].rrow;
	}
}
void getline(int num)//竖着一边manacher
{
	int circle = 1; int r = 1;
	t[1][num].rline = 1;
	for (int i = 2; i <= 2 * n - 1; i++)
	{
		if (circle + r - 1 > i)
			t[i][num].rline = min(circle + r - 1 - i + 1, t[2 * circle - i][num].rline);
		else
			t[i][num].rline = 1;
		while (i + t[i][num].rline <= 2 * n - 1 && i - t[i][num].rline >= 1 && t[i + t[i][num].rline][num].value == t[i - t[i][num].rline][num].value)t[i][num].rline++;
		if (i + t[i][num].rline > circle + r)circle = i, r = t[i][num].rline;
	}
}
void getrowans1(int num)//得到<-这个方向的最大距离 上下左右分别代表 1 2 3 4
{ 
	int l = 1; int r = 1; rst[l].pos = 1; rst[l].influence = t[num][1].rline; t[num][1].tr[4] = 1; rst[l].realpos = 1;
	int ll = 1; int rr = 1; height[ll].h = t[num][1].rline; height[ll].pos = 1;
	for (int i = 2; i <= 2 * m - 1; i++)
	{
		while (rst[l].realpos + rst[l].influence - 1 < i&&l <= r)l++;//如果栈首不能影响现在这个点那么出栈;
		if (l <= r)
		{
			while (height[ll].pos < rst[l].pos)ll++;//这个是height维护的作用,在能用的那些长度里面我们只能选最小的。(不知道如何维护单调栈的话可以做点题就明白了。
			t[num][i].tr[4] = min(height[ll].h, i - rst[l].pos + 1);//这我们取最小值
		}
		else
			t[num][i].tr[4] = 1;
		int  temppos = i; int temph = t[num][i].rline;
		while (l <= r&&rst[r].realpos + rst[r].influence - 1 >= i + t[num][i].rline - 1)temppos = rst[r].pos, r--;//更新栈
		while (ll <= rr&&temph <= height[rr].h)rr--;//更新
		r++; rr++;
		height[rr].h = temph; height[rr].pos = i;
		rst[r].influence = t[num][i].rline; rst[r].pos = temppos; rst[r].realpos = i; 
	}
}//后面的都一样了。。。
void getrowans2(int num)
{
	int l = 1; int r = 1; rst[l].pos = 2 * m - 1; rst[l].influence = t[num][2 * m - 1].rline; t[num][2 * m - 1].tr[2] = 1; rst[l].realpos = 2 * m - 1; 
	int ll = 1; int rr = 1; height[ll].h = t[num][2 * m - 1].rline; height[ll].pos = 2*m-1;
	for (int i = 2 * m - 2; i >= 1; i--)
	{
		while (rst[l].realpos - rst[l].influence + 1 > i&&l <= r)l++;
		if (l <= r)
		{
			while (height[ll].pos > rst[l].pos)ll++;
			t[num][i].tr[2] = min(height[ll].h, rst[l].pos - i + 1);
		}
		else
			t[num][i].tr[2] = 1;
		int temppos = i; int temph = t[num][i].rline;
		while (l <= r&&rst[r].realpos - rst[r].influence + 1 <= i - t[num][i].rline + 1)temppos = rst[r].pos,r--;
		while (ll <= rr&&temph <= height[rr].h)rr--;
		r++; rr++;
		height[rr].h = temph; height[rr].pos = i;
		rst[r].influence = t[num][i].rline; rst[r].pos = temppos; rst[r].realpos = i;
	}
}

void getans3(int num)
{
	int l = 1; int r = 1; lst[l].influence = t[1][num].rrow; t[1][num].tr[1] = 1; lst[l].realpos = 1; lst[l].pos = 1;
	int ll = 1; int rr = 1; height[ll].h = t[1][num].rrow; height[ll].pos = 1;
	for (int i = 2; i <= 2 * n - 1; i++)
	{
		while (lst[l].realpos + lst[l].influence - 1 < i&&l <= r)l++;
		if (l <= r)
		{
			while (height[ll].pos < lst[l].pos)ll++;
			t[i][num].tr[1] = min(height[ll].h, i - lst[l].pos + 1);
		}
		else
			t[i][num].tr[1] = 1;
		int temppos = i; int temph = t[i][num].rrow;
		while (l <= r&&lst[r].realpos + lst[r].influence - 1 >= i + t[i][num].rrow - 1)temppos = lst[r].pos, r--;
		while (ll<=rr&&temph < height[rr].h)rr--;
		r++; rr++;
		height[rr].pos = i; height[rr].h = temph;
		lst[r].influence = t[i][num].rrow; lst[r].pos = temppos; lst[r].realpos = i;
	}
}
void getans4(int num)
{
	int l = 1; int r = 1; lst[l].pos = 2 * n - 1; lst[l].influence = t[2 * n - 1][num].rrow; t[2 * n - 1][num].tr[3] = 1; lst[l].realpos = 2 * n - 1;
	int ll = 1; int rr = 1; height[ll].h = t[2 * n - 1][num].rrow; height[ll].pos = 2 * n - 1;
	for (int i = 2 * n - 2; i >= 1; i--)
	{
		while (lst[l].realpos - lst[l].influence + 1 > i&&l <= r)l++;
		if (l <= r)
		{
			while (height[ll].pos > lst[l].pos)ll++;
			t[i][num].tr[3] = min(height[ll].h, lst[l].pos - i + 1);
		}
		else
			t[i][num].tr[3] = 1;
		int temppos = i; int temph = t[i][num].rrow;
		while (l <= r&&lst[r].realpos - lst[r].influence + 1 <= i - t[i][num].rrow + 1)temppos = lst[r].pos, r--;
		while (ll <= rr&&temph < height[rr].h)rr--;
		r++; rr++;
		height[rr].h = temph; height[rr].pos = i;
		lst[r].influence = t[i][num].rrow; lst[r].pos = temppos; lst[r].realpos = i;
	}
}
int main()
{
	
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= 2 * n - 1; i += 2)
	{
		for (int j = 1; j <= 2 * m - 1; j++)
		{
			scanf("%d", &t[i][j].value);
			t[i][j + 1].value = 1000000001;
			j++;
		}
	}
	for (int i = 2; i <= 2 * (n - 1); i += 2)
	{
		for (int j = 1; j <= 2 * m - 1; j++)
		{
			t[i][j].value = 1000000001;
		}
	}
	for (int i = 1; i <= 2 * n - 1; i++)getrow(i);
	for (int i = 1; i <= 2 * m - 1; i++)getline(i);
	for (int i = 1; i <= 2 * n - 1; i++)getrowans1(i);
	for (int i = 1; i <= 2 * n - 1; i++)getrowans2(i);
	for (int i = 1; i <= 2 * m - 1; i++)getans3(i);
	for (int i = 1; i <= 2 * m - 1; i++)getans4(i);
	long long ans = 0;
	for (int i = 1; i <= 2 * n - 1; i++)
	{
		for (int j = 1; j <= 2 * m - 1; j++)
		{
			if ((i % 2 == 0 && j % 2 == 1) || (i % 2 == 1 && j % 2 == 0))continue;
			t[i][j].getans();
			if (t[i][j].value != 1000000001)
				ans += ((t[i][j].r - 1) / 2 + 1);
			else
				ans += t[i][j].r /2;
		}
	}
	printf("%lld\n", ans);
	return 0;
}//下面的题解中维护栈里面的各种高度时我们也用的是单调栈来维护的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值