牛客多校第7场J Sudoku Subrectangles

赛后看感觉是道水题,然而为撒考场上我们并没有想到枚举一个矩形的左上角或者右下角,再预处理出nxt[i][j],down[i][j]表示i,j点行和列上下一个会出现重复的位置,然后n*m*52去扫一遍,每个左上角顶点所能构成的答案矩形.

#include<cstdio>
#include<cstring>
#define maxl 1010

int n,m;
int last[maxl],lmt[maxl];
int a[maxl][maxl];
int nxt[maxl][maxl],down[maxl][maxl];
char s[maxl];
long long ans;

inline int gank(char ch)
{
	if(ch>='A' && ch<='Z') return ch-'A'+1;
	else return ch-'a'+1+26;
}

inline int min(int a,int b)
{
	if(a<b)
		return a;
	else
		return b;
}

inline void prework()
{
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)
			a[i][j]=gank(s[j]);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=52;j++)
			last[j]=m+1;
		nxt[i][m+1]=m+1;
		for(int j=m;j>=1;j--)
		{
			nxt[i][j]=min(nxt[i][j+1],last[a[i][j]]);
			last[a[i][j]]=j;
		}
	}
	for(int j=1;j<=m;j++)
	{
		for(int i=1;i<=52;i++)
			last[i]=n+1;
		down[n+1][j]=n+1;
		for(int i=n;i>=1;i--)
		{
			down[i][j]=min(down[i+1][j],last[a[i][j]]);
			last[a[i][j]]=i;
		}
	}
}

inline void mainwork()
{
	ans=0;int sz;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			lmt[j]=down[i][j];
			for(int k=j+1;k<nxt[i][j];k++)
				lmt[k]=min(lmt[k-1],down[i][k]);
			sz=nxt[i][j]-j;
			for(int k=i;k<down[i][j];k++)
			{
				sz=min(nxt[k][j]-j,sz);
				while(lmt[j+sz-1]<=k && sz>0)
					sz--;
				if(sz==0)
					break;
				ans+=sz;
			}
		}
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/81565248