cf1697 F. Too Many Constraints
作者:互联网
题意:
构造长度为 \(n\)、单调不降、值域为 \([1,k]\) 的数组。要求满足 \(m\) 个条件,条件有三种类型:
1 i x
表示 \(a_i\neq x\)2 i j x
表示 \(a_i+a_j\le x\)3 i j x
表示 \(a_i+a_j\ge x\)
\(2\le n\le 2e4, 0\le m\le 2e4, 2\le k\le 10\)
思路:
\(k\) 很小。开 \(nk\) 个点,\(p_{ik+x}=1\) 表示 \(a_i\ge x\),那就转化成 2-sat 问题
- (初始限制)
\(a_i\ge 1\)
\(a_i\le k\iff a_i<k+1\iff !(a_i\ge k+1)\)
\(a_i\ge x+1\implies a_i\ge x\)
\(a_i\ge x\implies a_{i+1}\ge x\)
- \(a_i\neq x\)
\(\iff a_i<x\or a_i\ge x+1\iff !(a_i\ge x)\or (a_i\ge x+1)\)
- \(a_i+a_j\le x\)
\(\forall y\),\(a_i\ge y \implies a_j\le x-y \iff a_j<x-y+1\iff !(a_j\ge x-y+1)\)
- \(a_i+a_j\ge x\)
\(\forall y\),\(!(a_i\ge y+1)\iff a_i<y+1\iff a_i\le y\implies a_j\ge x-y\)
为了写码方便,把值域写成 \([0,k+1]\)。
struct TwoSat {
int n;
vector<vector<int>> G;
vector<bool> ans;
TwoSat(int n) : n(n), G(2*n), ans(n) {}
void Or(int u, bool f, int v, bool g) { //至少一个为真
G[2*u+!f].pb(2*v+g), G[2*v+!g].pb(2*u+f);
}
void Implies(int u, bool f, int v, bool g) { //u=f → v=g
Or(u, !f, v, g);
}
void Xor(int u, bool f, int v, bool g) { //恰一个为真
Or(u, f, v, g), Or(u, !f, v, !g);
}
void Same(int u, bool f, int v, bool g) { //同时为真/假
Xor(u, !f, v, g);
}
void Must(int u, bool f) { //u=f
Or(u, f, u, f);
}
bool work() {
vector<int> id(2*n,-1), dfn(2*n,-1), low(2*n,-1), stk;
int now = 0, cnt = 0;
function<void(int)> tarjan = [&](int u) {
stk.pb(u);
dfn[u] = low[u] = now++;
for(auto v : G[u]) {
if(dfn[v] == -1) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(id[v] == -1) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
int v; do {
v = stk.back();
stk.pop_back();
id[v] = cnt;
} while (v != u);
++cnt;
}
};
for(int i = 0; i < 2*n; i++)
if(dfn[i] == -1) tarjan(i);
for(int i = 0; i < n; i++) {
if(id[2*i] == id[2*i+1]) return false;
ans[i] = id[2*i] > id[2*i+1];
}
return true;
}
};
void sol() {
int n, m, k; cin >> n >> m >> k;
int K = k + 2;
TwoSat ts(n*K); //未拆点的点数
#define p(i,x) (i)*K+x //a[i]取x的点号
for(int i = 0; i < n; i++) {
for(int x = 1; x <= k+1; x++)
ts.Implies(p(i,x), true, p(i,x-1), true);
ts.Must(p(i,1), true);
ts.Must(p(i,k+1), false);
}
for(int i = 1; i < n; i++)
for(int x = 0; x <= k+1; x++)
ts.Implies(p(i-1,x), true, p(i,x), true);
while(m--) {
int t, i, j, x; cin >> t;
if(t == 1) { //a[i]!=x
cin >> i >> x; i--;
ts.Or(p(i,x), false, p(i,x+1), true);
}
if(t == 2) { //a[i]+a[j]<=x
cin >> i >> j >> x; i--, j--;
for(int y = max(0,x-k); y <= min(k+1,x+1); y++)
ts.Implies(p(i,y), true, p(j,x-y+1), false),
ts.Implies(p(j,y), true, p(i,x-y+1), false);
}
if(t == 3) { //a[i]+a[j]>=x
cin >> i >> j >> x; i--, j--;
for(int y = max(0,x-k-1); y <= min(k,x); y++)
ts.Implies(p(i,y+1), false, p(j,x-y), true),
ts.Implies(p(j,y+1), false, p(i,x-y), true);
}
}
if(ts.work()) {
for(int i = 0, las = 0; i < n; i++) {
for(int x = 1; x <= k; x++)
if(ts.ans[p(i,x)]) las = x; //最后一个满足a[i]>=x的x
cout << las << " \n"[i == n-1];
}
}
else cout << -1 << endl;
}
标签:le,int,Many,cf1697,ge,bool,Too,id,low 来源: https://www.cnblogs.com/wushansinger/p/16480963.html