2022上海省赛(SHCPC)补题
待补
6题的时候离金还挺近的,看到那个差分约束瞬间想起来在acwing(或者洛谷)做过同样的题,然而死活回忆不出具体解法…
B Bracket Query
设\(s[i]\)为\(1到i\)中左括号减去右括号的数量,根据题意
\[\forall i,s[i]\ge 0\\
\forall i > 0 , \left | s[i] - s[i - 1] \right | = 1 \iff -1 \le s[i] - s[i - 1] \le1 \\
s[0] = s[n] = 0\\
\forall i \in (1, q), s[r_i] - s[l_i - 1] \ge c_i \\
\forall i \in (1, q), s[r_i] - s[l_i - 1] \le c_i
\]
最后两个约束条件,因为\(q\)很大,所以暴力连边会超时,发现本质不同的最多只有\(n\)个,可以用带权并查集维护。
最后建图跑spfa,判断是否出现负环即可。
为什么不会出现\(s[i]-s[i-1]=0\)的情况:
如果没有询问:因为边权都是正的,所以相邻的两个不会相等
如果有询问:如果询问合法,就保证了不会让相邻的两个奇偶性发生改变
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, PII> PPI;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 3000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int n, m;
int fa[N], val[N];
int dis[N], cnt[N], st[N];
int head[N], idx;
struct EGDE {
int to, next, w;
} eg[9000010];
void add(int x, int y, int w) {
eg[idx].to = y;
eg[idx].next = head[x];
eg[idx].w = w;
head[x] = idx++;
}
int find(int x) {
if (x == fa[x]) return x;
int px = fa[x];
fa[x] = find(fa[x]);
val[x] += val[px];
return fa[x];
}
void spfa() {
int ok = 1;
dis[0] = dis[n] = 0, add(n, 0, 0);
queue<int> q;
q.push(0), q.push(n);
while(q.size()) {
int cur = q.front();
q.pop();
if (cnt[cur] > n + 10) {
ok = 0;
break;
}
st[cur] = false;
for(int i = head[cur]; ~i; i = eg[i].next) {
int to = eg[i].to;
if(dis[to] > dis[cur] + eg[i].w) {
dis[to] = dis[cur] + eg[i].w;
cnt[to] = cnt[cur] + 1;
if(!st[to]) {
st[to] = true;
q.push(to);
}
}
}
}
if (dis[0] || dis[n]) ok = 0;
rep (i, 1, n) if (dis[i] < 0) ok = 0;
if (!ok) puts("?");
else {
printf("! ");
rep (i, 1, n) {
if (dis[i] - dis[i - 1] == 1) printf("(");
else printf(")");
}
puts("");
}
}
void work() {
scanf("%d%d", &n, &m);
rep (i, 0, n) head[i] = -1, dis[i] = INF;
rep (i, 1, n) fa[i] = i;
int ok = 1;
while (m--) {
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
u--;
if (((v - u) & 1) ^ (abs(d) & 1)) ok = 0;
int pu = find(u), pv = find(v);
if (pu != pv) {
fa[pv] = pu;
val[pv] = val[u] - val[v] - d;
add(u, v, d), add(v, u, -d);
}
else if (val[u] - val[v] != d) ok = 0;
}
rep (i, 1, n) add(i - 1, i, 1), add(i, i - 1, 1);
if (ok) spfa();
else puts("?");
}
signed main() {
IO
int test = 1;
while (test--) {
work();
}
return 0;
}