1. 程式人生 > >NOIP2014提高組模擬8.9

NOIP2014提高組模擬8.9

#include
#include

struct ecc{
	int se,fi,ln,la;
}b[1110*1100];

int a[1101][1101],n,m,i,j,k,g[1210*1200],tot;//g為連結串列頭指標,b.se為次小值,b.fi為最小值,b.ln行號,b.la為上一次的更新的地址
bool p;
int main(){

	scanf("%d%d",&n,&m);
	k=0;
	b[0].se=m+1;b[0].fi=m+1;
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			scanf("%d",&a[i][j]);p=0;
			if(i!=b[g[a[i][j]]].ln)++tot,k=tot,p=1;else k=g[a[i][j]];
			if(j<=b[g[a[i][j]]].fi){                    //更新最小次小值
				b[k].se=b[g[a[i][j]]].fi;
				b[k].fi=j;
				if(p)b[k].la=g[a[i][j]],g[a[i][j]]=k;
				b[k].ln=i;
			}else if(j<=b[g[a[i][j]]].se){
				b[k].se=j;
				b[k].fi=b[g[a[i][j]]].fi;
				if(p)b[k].la=g[a[i][j]],g[a[i][j]]=k;
				b[k].ln=i;
			}
		}
	}
	long long ans(0);int la;
	for(i=1;i<=n*m;i++){ //統計次數
		k=g[i];la=g[i];
		ans+=(n-b[la].ln+1)*(b[la].se-b[la].fi);//對於最後一次更新,b.ln~n行的最小次小區間的點為矩陣右下角的點的矩陣都是可行解
		ans%=19900907;
		if(!k)continue;
		while(k){
			if(k!=g[i])ans+=(b[la].ln-b[k].ln)*(b[k].se-b[k].fi),ans%=19900907;//計算每次更新間的答案
			la=k;
			k=b[k].la;
		}
	}
	printf("%lld",ans);
}