E. Tick, Tock

E. Tick, Tock

题意

给定一个n * m的矩阵,每个格子都有一个钟表,但只有有些格子中的时钟刻度已知,一次操作可以选定一行或一列将该行或该列的所有闹钟时刻都加1
每个钟表最大刻度是h,刻度取值范围是[0, h),操作后的钟表数字是(原数 + 1)%h,最后的目标是将所有格子的钟表的刻度都一样
问有多少中方案设置那些未知的钟表

思路

最后要刻度都一样 如果我们把刻度都弄成一样之后,再继续都加几个数,就能让它们变成相同的另一个数,那么我们不妨设这个最后的数为0
然后反向思考一下,就相当于一开始都是0,经过一系列操作,使得变成当前的刻度
对于一个有刻度的钟表,就相当于它的那行和那列加的次数取余h
对于一开始有刻度的格子我们将它的行和列连起来,即i和(j+n)连一条边,边权为a[i][j]
然后租后我们跑dfs根据已有的刻度给图上的每个点置数,因为如果两个点都没置过数 那一开始设什么都是一样的,那我们不妨设一个0和一个w
如果两个点有某一个已置数,那就给另一个置成(w - val[i] + h)%h,因为我们要保证两个数的和要等于a[i][j]。
如果两个点已经置数了但是它们的权值和不等于要求的a[i][j]那么说明不可能 直接-1
最后计算一下有多少个连通块(cnt) 每个连通块根据第一个点置数不同结果也不同,都有h种可能, 答案就是\(h^{cnt}\)

#include <bits/stdc++.h>
#include <stdlib.h>
using namespace std;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long
#define int ll
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 5;
const int M = 5e5 + 5;
const ll mod = 1e9 + 7;

int n, m, h, f, val[N * 2], vis[N * 2];
vector<pair<int, int> >g[N * 2];

int qpow(int base, int pow){
	int ans = 1;
	while(pow){
		if(pow & 1) ans = ans * base % mod;
		base = base * base % mod;
		pow >>= 1;
	}
	return ans;
}

void dfs(int x, int fa){
	vis[x] = 1;
	for(auto [to, w] : g[x]){
		if(to == fa) continue;
		
		if(val[x] == -1 && val[to] == -1) {
			val[x] = 0;
			val[to] = w;
		}
		else if(val[to] == -1) val[to] = (w - val[x] + h) % h;
		else if(val[x] == -1) val[x] = (w - val[x] + h) % h;
		else if((val[to] + val[x]) % h != w){
			f = 1;
			return;
		}

		if(!vis[to]) dfs(to, x);
	}
}

void solve()
{
	cin >> n >> m >> h;

	for(int i = 1; i <= n + m; i++){
		val[i] = -1;
		g[i].clear();
		vis[i] = 0;
	} 

	for(int i = 1; i <= n; i++){
		for(int j = 1, x; j <= m; j++){
			cin >> x;
			if(x == -1) continue;
			g[i].push_back({j + n, x});
			g[j + n].push_back({i, x});
		}
	}

	int cnt = 0;
	f = 0;
	for(int i = 1; i <= n + m; i++){
		if(!vis[i]){
			cnt++;
			val[i] = 0;
			dfs(i, -1);
			if(f) {
				cout << 0 << "\n";
				return;
			}
		}
	}

	cnt--;
	cout << qpow(h, cnt) << "\n";
}


signed main()
{
	IOS;
	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}
posted @ 2022-12-31 12:54  Yaqu  阅读(27)  评论(0编辑  收藏  举报