CF1697F

每一个 bool 变量表示「ai 是否 j」,由于 ai 必然 1,所以总的变量数是 n(k1)

然后我们根据题目条件来建有向边,注意 2-sat 要满足对称性,所以下文中每一个条件的逆否命题都要建边:

  • aiai+1,等价于「对于所有的 v,若 aiv,则 ai+1v」。
  • aix,等价于「若 aix,则 aix+1」。
  • ai+ajx,等价于「对于所有的 v,若 aiv,则 ¬(ajxv+1)」。
  • ai+ajx,等价于「对于所有的 v,若 ¬(aiv),则 ajxv+1」。

当然,还有最浅显的:

  • aiv,则 aiv1

麻烦的建图处理完后就是板子了。

Code:

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int N = 360005;
int T;
int n, m, k;
int dfn[N], low[N], tim;
int stk[N], top; bool vis[N];
int bel[N], scc_cnt;
vector <int> G[N];

void addedge(int x, int y) { G[x].pb(y); if (x != (y ^ 1)) G[y ^ 1].pb(x ^ 1); }
int num(int id, int x, bool y) { return ((id - 1) * (k - 1) + (x - 2)) << 1 | y; }
void build(int x) { for (int i = 2; i < k; ++i) addedge(num(x, i, 0), num(x, i + 1, 0)); }
void le(int x, int y) { for (int i = 2; i <= k; ++i) addedge(num(x, i, 1), num(y, i, 1)); }

void ne(int x, int val) {
	if (val == 1) addedge(num(x, 2, 0), num(x, 2, 1));
	else if (val == k) addedge(num(x, k, 1), num(x, k, 0));
	else addedge(num(x, val, 1), num(x, val + 1, 1));
}

void sumle(int x, int y, int val) {
	for (int i = 2; i <= k; ++i) {
		if (i >= val) addedge(num(x, i, 1), num(x, i, 0)), addedge(num(y, i, 1), num(y, i, 0));
		else if (i + k > val) addedge(num(x, i, 1), num(y, val - i + 1, 0));
	}
}

void sumge(int x, int y, int val) {
	for (int i = 2; i <= k; ++i) {
		if (i + k <= val) addedge(num(x, i, 0), num(x, i, 1)), addedge(num(y, i, 0), num(y, i, 1));
		else if (i < val) addedge(num(x, i, 0), num(y, val - i + 1, 1));
	}
}

void Tarjan(int u) {
	dfn[u] = low[u] = ++tim, vis[stk[++top] = u] = 1;
	for (int v : G[u]) {
		if (!dfn[v]) Tarjan(v), low[u] = min(low[u], low[v]);
		else if (vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if (low[u] == dfn[u]) {
		++scc_cnt;
		do {
			bel[stk[top]] = scc_cnt;
			vis[stk[top]] = 0;
			--top;
		} while (stk[top + 1] ^ u);
	}
}

void solve() {
	scanf("%d%d%d", &n, &m, &k);
	int tot = (k - 1) * n * 2;
	for (int i = 0; i < tot; ++i) G[i].clear();
	for (int i = 1; i <= n; ++i) build(i);
	for (int i = 1; i < n; ++i) le(i, i + 1);
	for (int i = 1, ty, x, y, val; i <= m; ++i) {
		scanf("%d", &ty);
		if (ty == 1) scanf("%d%d", &x, &val), ne(x, val);
		if (ty == 2) scanf("%d%d%d", &x, &y, &val), sumle(x, y, val);
		if (ty == 3) scanf("%d%d%d", &x, &y, &val), sumge(x, y, val);
	}
	memset(dfn, 0, sizeof (int) * tot), memset(bel, 0, sizeof (int) * tot), tim = top = scc_cnt = 0;
	for (int i = 0; i < tot; ++i) if (!dfn[i]) Tarjan(i);
	for (int i = 0; i < tot; i += 2) if (bel[i] == bel[i ^ 1]) return printf("%d\n", -1), void();
	for (int i = 1; i <= n; ++i) {
		int val = 1;
		for (int j = 2; j <= k; ++j) if (bel[num(i, j, 1)] < bel[num(i, j, 0)]) val = j;
		printf("%d ", val);
	}
	printf("\n");
}

int main() {
	scanf("%d", &T);
	while (T--) solve();
	return 0;
}
posted @   Kobe303  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示