https://www.nowcoder.com/acm/contest/145/J
题意:给出一个字符矩阵,只包含大小写字母,问有多少个子矩阵为字符数独(任意一行或一列没有重复字符)。
思路:
先预处理每个点往下往右能到最远的距离
然后枚举每个点为左上角,找能完全覆盖的子矩阵有多少个
答案会爆int
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1010;
char s[maxn][maxn];
int flag[maxn];
int righ[maxn][maxn];
int down[maxn][maxn];
int a[maxn][maxn];
int n,m;
int main()
{
ll ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
}
int cnt=0;
int k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cnt++;
for(k=j;k<=min(j+51,m);k++)
{
if(flag[s[i][k]]==cnt)
break;
flag[s[i][k]]=cnt;
}
righ[i][j]=k-j;
cnt++;
for(k=i;k<=min(i+51,n);k++)
{
if(flag[s[k][j]]==cnt)
break;
flag[s[k][j]]=cnt;
}
down[i][j]=k-i;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
a[i][j]=down[i][j];
int R=j+righ[i][j]-1;
for(k=j+1;k<=R;k++)
a[i][k]=min(a[i][k-1],down[i][k]);
ans+=righ[i][j];
int D=i+down[i][j]-1,now=j+righ[i][j]-1;
for(k=i+1;k<=D;k++)
{
now=min(now,j+righ[k][j]-1);
while(a[i][now]<k-i+1&&now>=j)
now--;
if(now<j)break;
ans=ans+now-j+1LL;
}
}
}
printf("%lld\n",ans);
return 0;
}