CF1697F Too Many Constraints 题解
看起来就像 2-sat。但每个点的取值为
注意到 bool 变量,其中第 bool 变量
显然此时要连接
至于为什么不拆成
取值型问题一般状态设计是变量
x\ge k 。形如x=k 的状态设计不好做,因为默认了x 的若干个状态中必须有且只有一个为\text{True} ,然而实际建图中无法建出这样的限制条件,也可能是我太菜了所以建不出。
那么对于题目中给出的若干种限制:
最后注意一下上面的下标显然会越界,越界的时候特判一下即可。如
然后你就做完了。(还挺套路的,除了建图真的麻烦
丑陋的代码:
// Problem: F. Too Many Constraints
// From: Codeforces - Educational Codeforces Round 130 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1697/problem/F
// Time: 2022-06-12 22:35
// Author: lingfunny
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int mxn = 2e4+10, mxz = 20*mxn;
int n, m, k, tot;
vector <int> G[mxz];
#define _(x) (x > tot ? x - tot : x + tot)
inline void add(int u, int v) { G[u].emplace_back(v);
// int u_ = u > tot ? u - tot : u, v_ = v > tot ? v - tot: v;
// printf("(%d, %d) %c -> (%d, %d) %c\n", u_%n?u_%n:n, (u_%n?u_/n:(u_-1)/n)+1, u>tot?'F':'T',
// v_%n?v_%n:n, (v_%n?v_/n:(v_-1)/n)+1, v>tot?'F':'T');
}
inline void dadd(int u, int v) { add(u, v), add(_(v), _(u)); }
int low[mxz], dfn[mxz], dfc, in[mxz], stk[mxz], top, scc[mxz], cnt;
void tarjan(int u) {
low[u] = dfn[u] = ++dfc, in[stk[++top] = u] = 1;
for(int v: G[u]) {
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(in[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u] && ++cnt) do scc[stk[top]] = cnt, in[stk[top]] = 0; while(stk[top--] != u);
}
inline void solve() {
scanf("%d%d%d", &n, &m, &k);
tot = n * k;
// printf("n = %d, m = %d, k = %d\n", n, m, k);
for(int i = 1; i <= tot*2; ++i) dfn[i] = 0, vector <int> ().swap(G[i]);
dfc = top = cnt = 0;
for(int p = 1; p <= n; ++p) for(int i = 1; i < k; ++i) dadd(p+(i-1)*n, p+i*n);
for(int p = 2; p <= n; ++p) for(int i = 1; i <= k; ++i) dadd(p+(i-1)*n, p-1+(i-1)*n);
add(2*tot, tot);
// puts("END");
for(int op, i, j, x; m--;) {
scanf("%d", &op);
if(op == 1) {
scanf("%d%d", &i, &x);
if(x == 1) add(i, _(i));
else dadd(i+(x-1)*n, i+(x-2)*n);
} else {
scanf("%d%d%d", &i, &j, &x);
if(op == 2) {
if(x-1 < k)
add(_(i+(x-2)*n), i+(x-2)*n),
add(_(j+(x-2)*n), j+(x-2)*n);
for(int p = 1; p <= k; ++p) {
int oth = x - p - 1;
if(oth >= 1 && oth <= k)
dadd(_(i+(p-1)*n), j+(oth-1)*n),
dadd(_(j+(p-1)*n), i+(oth-1)*n);
}
} else {
if(x-k > 1)
add(i+(x-k-2)*n, _(i+(x-k-2)*n)),
add(j+(x-k-2)*n, _(j+(x-k-2)*n));
for(int p = 1; p <= k; ++p) {
int oth = x - p - 1;
if(oth >= 1 && oth <= k)
dadd(i+(p-1)*n, _(j+(oth-1)*n)),
dadd(j+(p-1)*n, _(i+(oth-1)*n));
}
}
}
}
for(int i = 1; i <= 2*tot; ++i) if(!dfn[i]) tarjan(i);
for(int i = 1; i <= tot; ++i) if(scc[i] == scc[i+tot]) return puts("-1"), void();
for(int i = 1; i <= n; ++i) {
for(int p = 0; p < k; ++p) if(scc[i+p*n] < scc[_(i+p*n)]) { printf("%d%c", p+1, " \n"[i==n]); break; }
}
}
int main() {
int tt;
scanf("%d", &tt);
while(tt--) solve();
}