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;
}