Description
教主要带领一群Orzer到一个雄奇地方勘察资源。
这个地方可以用一个n×m的矩阵A[i, j]来描述,而教主所在的位置则是位于矩阵的第1行第1列。
矩阵的每一个元素A[i, j]均为一个不超过n×m的正整数,描述了位于这个位置资源的类型为第A[i, j]类。教主准备选择一个子矩阵作为勘察的范围,矩阵的左上角即为教主所在的(1, 1)。若某类资源k在教主勘察的范围内恰好出现一次。或者说若教主选择了(x, y)即第x行第y列作为子矩阵的右下角,那么在这个子矩阵中只有一个A[i, j](1≤i≤x,1≤j≤y)满足A[i, j]=k,那么第k类资源则被教主认为是稀有资源。
现在问题是,对于所有的(x, y),询问若(x, y)作为子矩阵的右下角,会有多少类不同的资源被教主认为是稀有资源。
Input
输入的第一行包括两个正整数n和m,接下来n行,每行m个数字,描述了A[i, j]这个矩阵。
Output
为了照顾Vijos脑残的输出问题,设B[i, j]表示仅包含前i行与前j列的子矩阵有多少个数字恰好出现一次,那么你所要输出所有B[i, j]之和mod 19900907。
分析
见代码,无路赛
细节多的有病,想死。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int f[2001][2001];
int y[2000001];
int x[2000001][3];
long long ans;
int n,m;
void init()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&f[i][j]);
}
int main()
{
init();
for (int i=1;i<=n*m;i++)
{
x[i][1]=m+1;
x[i][2]=m+1;
}
ans=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int a=f[i][j];
if ((x[a][1]<=j)&&(x[a][2]>=j))
{
if (x[a][2]!=m+1)
ans+=((i-y[a]-1)*(x[a][2]-x[a][1])+(j-x[a][1]))%19900907;
else
ans+=((i-y[a])*(x[a][2]-x[a][1])+(j-x[a][1]))%19900907;
x[a][2]=j;
y[a]=i;
}
else
if (x[a][1]>j)
{
if (x[a][1]!=m+1)
if (x[a][2]!=m+1)
ans+=((i-y[a]-1)*(x[a][2]-x[a][1])+(x[a][1]-j))%19900907;
else
{
ans+=((i-y[a]-1)*(x[a][2]-x[a][1])+(x[a][1]-j))%19900907;
ans+=(x[a][2]-x[a][1])%19900907;
}
x[a][2]=x[a][1];
x[a][1]=j;
y[a]=i;
}
}
for (int i=1;i<=n*m;i++)
if (x[i][1]<=m)
if (x[i][2]!=m+1)
ans+=((x[i][2]-x[i][1])*(n-y[i]))%19900907;
else
ans+=((x[i][2]-x[i][1])*(n-y[i]+1))%19900907;
ans=ans%19900907;
printf("%lld",ans);
}