Codeforces 1080E-Sonya and Matrix Beauty

Codeforces 1080E-Sonya and Matrix Beauty

题意

给出一个N*M的矩阵,问其有多少个子矩阵是“美丽矩阵”。
美丽矩阵:
选定矩阵后,可以在对矩阵的每一行中的元素任意调换位置,使该矩阵的每一行、每一列均是回文串。

题解

先对每一行用计数数组哈希,并考虑是否能够构成回文串。然后考虑列,枚举左右端点,Manacher计算回文串数量。

代码

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&-x)
typedef long long ll;
const int N=1e3+10;
const int base=131;
const ll mod=1e9+7;
char s[N][N];
int a[N][N];
int cnt[N][N][30];
ll Hash[N][N];
ll val[N][N];
ll tmp[N<<1];
int n,m;
ll ans;

ll getHash(int i,int j){
	ll res=0;
	for(int k=1;k<=26;k++) res=(res*base%mod+cnt[i][j][k])%mod;
	return res;
}

bool check(int k,int i,int j){
	ll x=val[k][j]^val[k][i-1];
	if(!x||!(x-lowbit(x))) return 1;
	return 0;
}

int d[N];

void Manacher(){
	memset(d,0,sizeof(d));
	int l=1,r=0;
	for(int i=1;i<=2*n+1;i++){
		if(tmp[i]<0) continue;
		int k=(i>r)?0:min(r-i,d[l+r-i]);
		while(i-k>=1&&i+k<=2*n+1&&tmp[i-k]==tmp[i+k]) k++;
		d[i]=k--;
		if(i+k>r){
			l=i-k;
			r=i+k;
		}
		ans+=(ll)d[i]/2;
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=s[i][j]-'a'+1;
		}
	}
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=1;k<=26;k++){
				cnt[i][j][k]=cnt[i][j-1][k];
			}
			cnt[i][j][a[i][j]]++;
			Hash[i][j]=getHash(i,j);
			val[i][j]=val[i][j-1]^(1<<a[i][j]);
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=i;j<=m;j++){
			for(int k=1;k<=n;k++){
				tmp[k*2-1]=0;
				if(check(k,i,j)) tmp[k<<1]=(Hash[k][j]-Hash[k][i-1]+mod)%mod;
				else tmp[k<<1]=-k;
			}
			tmp[2*n+1]=0;
			Manacher();
		}
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/qjy73/p/12622107.html