【题解】CF1697F-Too Many Constraints
构造一个长度为 \(n\) 的不降序列 \(a\),满足 \(a_i\in[1,k]\),并且满足若干个形如 \(a_i\neq x,a_i+a_j \le x,a_i+a_j \ge x\) 的条件。
观察到 \(k\) 非常小,考虑拆点的图论建模。
把每个点拆成 \(k\) 个点,然后跑 2-SAT 模型。\(p_{i,j}\) 为真表示 \(a_i = j\),然后将条件连边即可。
但是这么做无法构造方案。因为这样建模,每个点拆出的 \(k\) 个点中,至少要恰好有一个点为真,但是 2-SAT 模型只能保证最多一个点为真。
考虑构造另外一种方式,我们进行前缀转化,其中 \(p_{i,j}\) 为真表示 \(a_i \ge j\),那么每个点拆出的 \(k\) 个点,一定是前面一段为真,后面一段为假,这个条件可以简单处理。然后再把输入的限制连边即可。时间复杂度 \(\mathcal{O}(nk^2)\)。
#define N 400005
#define M 20005
#define S 20000005
int n, m, k, idx, id[M][11][2], tot, h[N], num, top, cnt, sta[N], v[N], dfn[N], low[N], col[N];
struct edge{int to, nxt;}e[S];
void add(int x,int y){e[++tot].nxt = h[x], h[x] = tot, e[tot].to = y;}
void dfs(int x){
dfn[x] = low[x] = ++idx, v[sta[++top] = x] = 1;
for(int i = h[x]; i; i = e[i].nxt){
int y = e[i].to;
if(!dfn[y])dfs(y), cmn(low[x], low[y]);
else if(v[y])cmn(low[x], dfn[y]);
}
if(dfn[x] == low[x]){
++cnt;
while(true){
int y = sta[top--];
v[y] = 0, col[y] = cnt;
if(x == y)break;
}
}
}
void solve(){
read(n, m, k), idx = tot = num = cnt = 0;
rp(i, n)rp(j, k)rep(t, 0, 1)id[i][j][t] = ++num;
rp(i, num)dfn[i] = low[i] = col[i] = h[i] = 0;
rp(i, n){
rp(x, k - 1)add(id[i][x][0], id[i][x + 1][0]), add(id[i][x + 1][1], id[i][x][1]);
if(i < n)rp(x, k)add(id[i][x][1], id[i + 1][x][1]), add(id[i + 1][x][0], id[i][x][0]);
add(id[i][1][0], id[i][1][1]);
}
while(m--){
int op, x, y, z;
read(op, x, y);
if(1 == op){
if(y == k)add(id[x][y][1], id[x][y][0]);
else add(id[x][y][1], id[x][y + 1][1]), add(id[x][y + 1][0], id[x][y][0]);
}
else {
read(z);
if(2 == op){
rp(l, k)rp(r, k)if(l + r > z){
if(l > z)add(id[x][l][1], id[x][l][0]);
if(r > z)add(id[y][r][1], id[y][r][0]);
add(id[x][l][1], id[y][r][0]), add(id[y][r][1], id[x][l][0]);
}
}
else{
rp(l, k)rp(r, k){
if(l + k - 1 < z)add(id[x][l][0], id[x][l][1]);
if(r + k - 1 < z)add(id[y][r][0], id[y][r][1]);
if(l + r - 1 <= z)
add(id[x][l][0], id[y][r][1]), add(id[y][r][0], id[x][l][1]);
}
}
}
}
rp(i, num)if(!dfn[i])dfs(i);
rp(i, n)rp(j, k)if(col[id[i][j][0]] == col[id[i][j][1]]){puts("-1"); return;}
rp(i, n)pr(j, k)if(col[id[i][j][0]] > col[id[i][j][1]]){printf("%d ", j); break;}
el;
}
int main() {int T; read(T); while(T--)solve();}