题目
题解思路
首先探讨二维转一维的思路。
将每个点转成横坐标乘N+纵坐标。看起来可以实现,但是这题需要四周的点,这样3 4 就被隐式连接了。所以会Wa。
当我们先将N自增1的时候,每个能用上的XY就不会出现上面那种隐式连接了。(小技巧)
然后回到这题,当一个1变成0的时候,四周的1也会变成0,即连锁反应。
所以我们可以将每个有这种关系的点连通成块。
想将所有1变成0必然是按每个连通块中的一个就行。
假设有N个连通块,每个连通块有a1 a2…an个点。
这样选择的情况就是N!a1a2*a3…*an。
每次选一个连通块,再从连通块中选一个点。
这样我们可以预处理出当前的答案。
然后处理修改问题。
首先将1 变成 1 没有影响答案。直接输出。
将0变成1,有可能会将几个连通块连接到一起,也可能只增加一个连通块。
如果分类讨论,代码将变得非常复杂且长。
不如考虑一般性,连接一个改变一次答案。
当为0变1的时间先将cnt++,然后更新答案(乘新的个数)。(即假定他只是增加了一个块。)
之后每连通一个,就按上面的公式,先除个数再除乘积最后乘回总和。然后将连通块相连。
由于之前的答案可能以及被取模了(乘阶乘是很恐怖的)但是除法无法保证取模的同余。所以我们要用到逆元,将除法变成乘法。
最后输出。
这题是不错的题目,学到了不少。
AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7 ;
const int N = 510 ;
int n ;
int cnt = 0 ;
char mp[N][N] ;
int a[N*N] ;
int sz[N*N] ;
int dx[4] = {0,0,-1,1} ;
int dy[4] = {1,-1,0,0} ;
long long qsm(long long a, long long b)
{
long long ans = 1, t = a;
while(b)
{
if (b & 1) ans = ans *t % mod;
t = t * t % mod;
b >>= 1;
}
return ans % mod;
}
long long ni(long long x )
{
return qsm(x,mod-2) ;
}
int find(int x )
{
if (a[x] != x ) a[x] = find(a[x]);
return a[x] ;
}
void uio(int x ,int y )
{
int fx = find(x) ;
int fy = find(y) ;
if (fx != fy )
{
a[fy] = fx ;
sz[fx] += sz[fy] ;
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n ;
cin >> n ;
for (int i = 1 ; i <= n ; i++ )
cin >> mp[i] + 1 ;
for (int i = 0 ; i <= n*n ; i++ )
{
a[i] = i ;
sz[i] = 1 ;
}
for (int i = 1 ; i <= n ; i++ )
{
for (int j = 1 ; j <= n ; j++ )
{
if (mp[i][j] == '1')
{
if (mp[i-1][j] == '1')
uio(i*n+j,(i-1)*n+j);
if (mp[i][j-1] == '1')
uio(i*n+j,i*n+j-1);
if (mp[i+1][j] == '1')
uio(i*n+j,(i+1)*n+j);
if (mp[i][j+1] == '1')
uio(i*n+j,i*n+j+1);
}
}
}
long long cnt = 0 ;
long long ans = 1 ;
for (int i = 1 ; i <= n ; i++ )
{
for (int j = 1 ; j <= n ; j++ )
{
if (a[i*n+j] == i*n+j && mp[i][j] == '1' )
{
cnt ++ ;
ans = (sz[i*n+j]*ans )% mod ;
}
}
}
for (int i = 1 ; i <= cnt ; i++ )
{
ans = (ans * i) %mod ;
}
int k ;
cin >> k ;
for (int i = 1 ; i <= k ; i++ )
{
int t1 , t2 ;
cin >> t1 >> t2 ;
t1++,t2++;
if (mp[t1][t2] == '1')
{
cout << ans << "\n" ;
continue ;
}
cnt ++ ;
ans = ans * cnt % mod ;
mp[t1][t2] = '1' ;
for (int j = 0 ; j < 4 ; j++ )
{
int fx = t1 + dx[j] ;
int fy = t2 + dy[j] ;
if (mp[fx][fy] == '1')
{
int k1 = find(fx*n+fy) ;
int k2 = find(t1*n+t2) ;
if (k1 != k2 )
{
ans = ans*ni(cnt) % mod ;
ans = ans*ni(sz[k1]) % mod ;
ans = ans*ni(sz[k2]) % mod ;
ans = ans*(sz[k1]+sz[k2]) %mod ;
cnt--;
uio(k1,k2) ;
}
}
}
cout << ans << "\n" ;
}
return 0 ;
}