EOJ Monthly 2018.10 - C 痛苦的 01 矩阵 (数学推导)

版权声明:是自己手打的没错 https://blog.csdn.net/Mr_Treeeee/article/details/82934112

https://acm.ecnu.edu.cn/contest/113/problem/C/

POINT:

用 r_{i} 表示第i行有多少个 0,用 c_{j}表示第 j 列有多少个 0,bij 表示第 i 行第 j 列是否为 0。则 cost(i,j)=r_{i}+c_{j}b_{i,j}

cost(i,j)^{2}=r_{i}^{2}+c_{j}^{2}+b_{i,j}^{2}+2*c_{j}*r_{i}-2*r_{i}*b_{i,j}-2*c_{j}*b_{i,j}

设C为全矩阵0的个数。

ans=\sum_{i=1}^{n}\sum_{j=1}^{n}cost(i,j)^{2}

\sum_{i=1}^{n}\sum_{j=1}^{n}r_{i}^{2}+c_{j}^{2}+b_{i,j}^{2}=n*\sum_{i=1}^{n}r_{i}^{2}+n*\sum_{i=1}^{n}c_{j}^{2}+C

\sum_{i=1}^{n}\sum_{j=1}^{n}2*c_{j}*r_{i}=2C^{2}

\sum_{i=1}^{n}\sum_{j=1}^{n}2*r_{i}*b_{i,j}=2*r_{i}^{2}

同理求和2cb=2c^2。

所以得

ans=(n-2)\sum_{i=1}^{n}r_{i}^{2}+(n-2)\sum_{i=1}^{n}c_{i}^{2}+2*C^{2}+C

每次修改操作至多只会影响一个 ci 和一个 ri,将原来的 ci,ri,C 的贡献撤回,然后重新计算贡献即可。

对原题解做了一些补充,注意取模。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <map>
using namespace std;

const int N = 2e5 + 10;
typedef  pair<int,int> pii;
#define LL long long
const LL mod = 1e9+7;

map<pii,int> mp;

LL r[N],c[N];

int main()
{
	LL n,k,Q;
	scanf("%lld%lld%lld",&n,&k,&Q);
	LL C=(n*n%mod-k+mod)%mod;
	for(LL i=1;i<=n;i++) r[i]=c[i]=n;
	for(LL i=1;i<=k;i++){
		LL x,y;scanf("%lld%lld",&x,&y);
		mp[make_pair(x,y)]=1;
		r[x]--;c[y]--;
	}
	LL ans=0;
	LL a=0,b=0;
	for(LL i=1;i<=n;i++){
		a+=c[i]*c[i];
		a%=mod;
		b+=r[i]*r[i];
		b%=mod;
	}
	ans=(n-2)*(a+b)%mod+2*C*C%mod+C;
	ans%=mod;
	printf("%lld\n",ans);
	while(Q--){
		LL x,y;scanf("%lld%lld",&x,&y);
		ans-=((n-2)*(r[x]*r[x]%mod+c[y]*c[y]%mod)%mod+2*C*C%mod+C)%mod;
		ans=(ans+mod)%mod;
		if(mp[make_pair(x,y)]==1){
			r[x]++;c[y]++;C++;
			ans+=((n-2)*(r[x]*r[x]%mod+c[y]*c[y]%mod)%mod+2*C*C%mod+C)%mod;
			ans%=mod;
			mp[make_pair(x,y)]=0;
		}else{
			r[x]--;c[y]--;C--;
			C=(C+mod)%mod;
			ans+=((n-2)*(r[x]*r[x]%mod+c[y]*c[y]%mod)%mod+2*C*C%mod+C)%mod;
			ans%=mod;
			mp[make_pair(x,y)]=1;
		}
		printf("%lld\n",ans);
	}


	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mr_Treeeee/article/details/82934112