Codeforces 528C Data Center Drama

考虑存在解的必要条件,显然,各个点的度数应为偶数,且 MMM 也应为偶数。

任意一张满足以上条件的图都存在一条长度为偶数的欧拉回路,取路上奇数位的边为正向,偶数位的边为反向即可构造一组解法。

因此,任意用最少的步数将图改造为满足以上条件的图即可。

时间复杂度 O(N+M)O(N+M)O(N+M) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
bool vis[MAXN];
unsigned cur[MAXN];
vector <int> ans, points;
vector <pair <int, int>> a[MAXN];
void work(int pos) {for (unsigned &i = cur[pos]; i < a[pos].size(); i++)if (!vis[a[pos][i].second]) {vis[a[pos][i].second] = true;work(a[pos][i].first);}ans.push_back(pos);
}
int main() {int n, m; read(n), read(m);for (int i = 1; i <= m; i++) {int x, y; read(x), read(y);a[x].emplace_back(y, i);a[y].emplace_back(x, i);}vector <int> points;for (int i = 1; i <= n; i++)if (a[i].size() & 1) points.push_back(i);while (!points.empty()) {int x = points.back(); points.pop_back();int y = points.back(); points.pop_back(), m++;a[x].emplace_back(y, m);a[y].emplace_back(x, m);}if (m & 1) {m++;a[1].emplace_back(1, m);a[1].emplace_back(1, m);}printf("%d\n", m); work(1);for (int i = 1; i <= m; i++)if (i & 1) printf("%d %d\n", ans[i - 1], ans[i]);else printf("%d %d\n", ans[i], ans[i - 1]);return 0;
}

Codeforces 536D Tavas in Kansas

首先求出最短路,并离散化。

不难得到动态规划解法,记 dpi,j,0/1dp_{i,j,0/1}dpi,j,0/1​ 表示仅考虑到 SSS 距离在 iii 以上,到 TTT 距离在 jjj 以上的点,先手 / 后手玩家能够取到的最优分差,转移显然可以枚举下一步如何行动。

观察转移,用前缀和优化之即可。

时间复杂度 O(N2+MLogN)O(N^2+MLogN)O(N2+MLogN) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e3 + 5;
const long long INF = 1e18;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
namespace ShortestPath {const ll INF = 1e18;const int MAXP = 1e6;struct edge {int dest, len; };int n; ll dist[MAXP];vector <edge> a[MAXP];set <pair <ll, int> > st;void addedge(int x, int y, int z) {a[x].push_back((edge) {y, z});}void init(int x) {n = x; st.clear();for (int i = 1; i <= n; i++) {dist[i] = INF;a[i].clear();}}void work(int s) {dist[s] = 0;for (int i = 1; i <= n; i++)if (s != i) dist[i] = INF;st.insert(make_pair(0, s));while (!st.empty()) {pair <ll, int> tmp = *st.begin();st.erase(tmp);for (unsigned i = 0; i < a[tmp.second].size(); i++) {int dest = a[tmp.second][i].dest;ll newlen = tmp.first + a[tmp.second][i].len;if (newlen < dist[dest]) {st.erase(make_pair(dist[dest], dest));dist[dest] = newlen;st.insert(make_pair(dist[dest], dest));}}}}
}
int n, m, s, t;
int p[MAXN], x[MAXN], y[MAXN];
int cnt[MAXN][MAXN]; ll sum[MAXN][MAXN];
ll dp[MAXN][MAXN][2], aux[MAXN][MAXN][2];
void makecor(ll *x, int *y) {set <ll> st; map <ll, int> res;for (int i = 1; i <= n; i++)st.insert(x[i]);int tot = 0;for (auto x : st) res[x] = ++tot;for (int i = 1; i <= n; i++)y[i] = res[x[i]];
}
int calcnt(int lx, int rx, int ly, int ry) {return cnt[rx][ry] - cnt[rx][ly - 1] - cnt[lx - 1][ry] + cnt[lx - 1][ly - 1];
}
ll calsum(int lx, int rx, int ly, int ry) {return sum[rx][ry] - sum[rx][ly - 1] - sum[lx - 1][ry] + sum[lx - 1][ly - 1];
}
void debug() {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++)printf("(%4lld,%4lld) ", dp[i][j][0], dp[i][j][1]);printf("\n");}
}
int main() {read(n), read(m), read(s), read(t);for (int i = 1; i <= n; i++)read(p[i]);ShortestPath :: init(n);for (int i = 1; i <= m; i++) {int x, y, z;read(x), read(y), read(z);ShortestPath :: addedge(x, y, z);ShortestPath :: addedge(y, x, z);}ShortestPath :: work(s);makecor(ShortestPath :: dist, x);ShortestPath :: work(t);makecor(ShortestPath :: dist, y);for (int i = 1; i <= n; i++) {cnt[x[i]][y[i]]++;sum[x[i]][y[i]] += p[i];}for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) {cnt[i][j] += cnt[i - 1][j] + cnt[i][j - 1] - cnt[i - 1][j - 1];sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];}for (int i = n; i >= 1; i--)for (int j = n; j >= 1; j--) {aux[i][j][0] = dp[i + 1][j][1] + sum[i][n] - sum[i][j - 1];if (i != n) chkmax(aux[i][j][0], aux[i + 1][j][0]);if (calcnt(i, i, j, n) == 0) dp[i][j][0] = dp[i + 1][j][0];else dp[i][j][0] = aux[i][j][0] + sum[i - 1][j - 1] - sum[i - 1][n];aux[i][j][1] = dp[i][j + 1][0] - sum[n][j] + sum[i - 1][j];if (j != n) chkmin(aux[i][j][1], aux[i][j + 1][1]);if (calcnt(i, n, j, j) == 0) dp[i][j][1] = dp[i][j + 1][1];else dp[i][j][1] = aux[i][j][1] - sum[i - 1][j - 1] + sum[n][j - 1];}//debug();if (dp[1][1][0] > 0) puts("Break a heart");else if (dp[1][1][0] == 0) puts("Flowers");else puts("Cry");return 0;
}

Codeforces 538G Berserk Robot

首先,令对于点 (x,y)(x,y)(x,y) ,令 x=x+y,y=x−yx=x+y,y=x-yx=x+y,y=x−y 。
并令 R=(+1,+1),U=(+1,−1),L=(−1,−1),D=(+1,−1)R=(+1,+1),U=(+1,-1),L=(-1,-1),D=(+1,-1)R=(+1,+1),U=(+1,−1),L=(−1,−1),D=(+1,−1) 。

旋转坐标系后,可以认为 x,yx,yx,y 两维是分立的,我们只需要分别解决一维的问题就可以了。

以 xxx 坐标为例,令 sis_isi​ 表示串中前 iii 个元素的前缀和,则每条限制可以被描述为 sti%L=xi−⌊tiL⌋sns_{t_i\% L}=x_i-\lfloor\frac{t_i}{L}\rfloor s_nsti​%L​=xi​−⌊Lti​​⌋sn​ 。并且, sis_isi​ 需要额外满足 si≡i(mod2)s_i\equiv i\ (\bmod 2)si​≡i (mod2) 。

那么,考虑相邻的两个有限制的 si,sj(i<j)s_i,s_j\ (i<j)si​,sj​ (i<j) ,则有不等式 ∣si−sj∣≤j−i|s_i-s_j|\leq j-i∣si​−sj​∣≤j−i ,可以解出一个 sns_nsn​ 的范围。取所有限制的并,任取一个限制内的 sns_nsn​ 即可。

时间复杂度 O(N+L)O(N+L)O(N+L) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXL = 2e6 + 5;
const long long INF = 4e18;
typedef long long ll;
template <typename T> T abs(T x) {if (x <= 0) return -x; else return x; }
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
int n, l; bool vis[MAXL];
ll t[MAXN], x[MAXN], y[MAXN];
pair <ll, ll> px[MAXL], py[MAXL];
ll solve(pair <ll, ll> x, pair <ll, ll> y) {if ((y.first - x.first) % (y.second - x.second) == 0)return (y.first - x.first) / (y.second - x.second);puts("NO"), exit(0);return -1;
}
ll Ceil(ll x, ll y) {ll tmp = INF / y;return (x + tmp * y) / y - tmp + 1;
}
ll Round(ll x, ll y) {ll tmp = INF / y;return (x + tmp * y) / y - tmp;
}
pair <ll, ll> calc(pair <ll, ll> x, pair <ll, ll> y, ll k) {if (y.second == x.second) {ll delta = abs(x.first - y.first);if (delta <= k) return make_pair(-l, l);else return make_pair(INF, -INF);}if (y.second < x.second) swap(x, y);ll coef = y.second - x.second, delta = y.first - x.first;ll Min = delta - k, Max = delta + k; pair <ll, ll> ans;if (Min % coef == 0) ans.first = Min / coef;else ans.first = Ceil(Min, coef);if (Max % coef == 0) ans.second = Max / coef;else ans.second = Round(Max, coef);return ans;
}
int main() {read(n), read(l);pair <ll, ll> limx, limy;limx = limy = make_pair(-l, l);vis[0] = true;for (int i = 1; i <= n; i++) {read(t[i]), read(x[i]), read(y[i]);ll tx = x[i] + y[i], ty = x[i] - y[i];x[i] = tx, y[i] = ty;if (abs(x[i]) % 2 != t[i] % 2 || abs(y[i]) % 2 != t[i] % 2) {puts("NO");return 0;}ll Mod = t[i] % l, Div = t[i] / l;if (vis[Mod]) {chkmax(limx.first, solve(px[Mod], make_pair(x[i], Div)));chkmin(limx.second, solve(px[Mod], make_pair(x[i], Div)));chkmax(limy.first, solve(py[Mod], make_pair(y[i], Div)));chkmin(limy.second, solve(py[Mod], make_pair(y[i], Div)));} else {vis[Mod] = true;px[Mod] = make_pair(x[i], Div);py[Mod] = make_pair(y[i], Div);}}vis[l] = true, px[l] = py[l] = make_pair(0, -1);for (int i = 1, last = 0; i <= l; i++)if (vis[i]) {pair <ll, ll> tmp;tmp = calc(px[last], px[i], i - last);chkmax(limx.first, tmp.first);chkmin(limx.second, tmp.second);tmp = calc(py[last], py[i], i - last);chkmax(limy.first, tmp.first);chkmin(limy.second, tmp.second);last = i;}if (abs(limx.first) % 2 != l % 2) limx.first++;if (abs(limy.first) % 2 != l % 2) limy.first++;if (limx.first > limx.second || limy.first > limy.second) {puts("NO");return 0;}ll sumx = limx.first, sumy = limy.first;static bool ansx[MAXL], ansy[MAXL];for (int i = 1, last = 0; i <= l; i++)if (vis[i]) {ll now, goal;now = px[last].first - px[last].second * sumx;goal = px[i].first - px[i].second * sumx;for (int j = last + 1; j <= i; j++)if (now <= goal) {ansx[j] = true;now++;} else now--;assert(now == goal);now = py[last].first - py[last].second * sumy;goal = py[i].first - py[i].second * sumy;for (int j = last + 1; j <= i; j++)if (now <= goal) {ansy[j] = true;now++;} else now--;assert(now == goal);last = i;}for (int i = 1; i <= l; i++) {if (ansx[i]) {if (ansy[i]) putchar('R');else putchar('U');} else {if (ansy[i]) putchar('D');else putchar('L');}}puts("");return 0;
}

Codeforces 538H Summer Dichotomy

首先,若给定的图不是二分图,则显然无解。

考虑图是二分图的情况,每个联通块可以用其两侧点对应区间的交来描述。

考虑一个划分方案,使得 111 集合内区间的并为 [l1,r1][l_1,r_1][l1​,r1​] , 222 集合内区间的并为 [l2,r2][l_2,r_2][l2​,r2​] ,并且存在一个合法方案。那么,一定存在另一个合法方案使得 n1n_1n1​ 是 l1,l2l_1,l_2l1​,l2​ 中的一者,且 n2n_2n2​ 是 r1,r2,T−n1r_1,r_2,T-n_1r1​,r2​,T−n1​ 中的一者,或者 n1n_1n1​ 是 $r_1,r_2 $ 中的一者,且 n2n_2n2​ 是 l1,l2,t−n1l_1,l_2,t-n_1l1​,l2​,t−n1​ 中的一者。

枚举这两种情况,以第一种为例。

对所有区间按照左端点排序,并枚举 n1n_1n1​ ,考虑如何计算 n2n_2n2​ 。

左端点在 n1n_1n1​ 右侧的区间必须分在 222 集合内,因此不能包含同一连通块对应的所有区间。令 MrM_rMr​ 表示这些区间的右端点最小值, MlM_lMl​ 表示这些区间的左端点最大值。

左端点在 n1n_1n1​ 左侧或相同的区间必须覆盖 n1n_1n1​ ,若同一连通块对应的所有区间左端点均在 n1n_1n1​ 左侧或与 n1n_1n1​ 相同,应取右端点较大者划入 222 集合,令 MxM_xMx​ 这些区间的右端点最小值。

若存在合法的 (n1,n2)(n_1,n_2)(n1​,n2​) , n2n_2n2​ 应当取 T−n1,Mx,MrT-n_1,M_x,M_rT−n1​,Mx​,Mr​ 的最小值,且应 ≥Ml\geq M_l≥Ml​ 。

实现可以参考以下代码,时间复杂度 O(NLogN+M)O(NLogN+M)O(NLogN+M) 。

在 Codeforces 的讨论版中存在一种较为简便的做法:

不考虑 t,Tt,Tt,T 的限制,则显然应取 n1=max⁡(li),n2=min⁡(ri)n_1=\max(l_i),n_2=\min(r_i)n1​=max(li​),n2​=min(ri​) ,判断 (n1,n2)(n_1,n_2)(n1​,n2​) 是否合法即可。

若 t>n1+n2t>n_1+n_2t>n1​+n2​ ,则令 n1=n1+(t−n1−n2)n_1=n_1+(t-n_1-n_2)n1​=n1​+(t−n1​−n2​) ;
若 n1+n2>Tn_1+n_2>Tn1​+n2​>T ,则令 n2=n2−(n1+n2−T)n_2=n_2-(n_1+n_2-T)n2​=n2​−(n1​+n2​−T) ,然后判断 (n1,n2)(n_1,n_2)(n1​,n2​) 是否合法即可。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int INF  = 1e9 + 7;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
int n, m, tot, ans[MAXN];
bool vis[MAXN], col[MAXN];
vector <int> e[MAXN], points[MAXN];
pair <int, int> s, tmp[2], v[MAXN], a[MAXN][2];
void foundAns(int x, int y) {assert(s.first <= x + y && x + y <= s.second);puts("POSSIBLE");printf("%d %d\n", x, y);static int ans[MAXN];for (int i = 1; i <= tot; i++) {if (a[i][0].first <= x && x <= a[i][0].second && a[i][1].first <= y && y <= a[i][1].second) {for (auto x : points[i])ans[x] = col[x];} else if (a[i][0].first <= y && y <= a[i][0].second && a[i][1].first <= x && x <= a[i][1].second) {for (auto x : points[i])ans[x] = !col[x];} else assert(false);}for (int i = 1; i <= n; i++)printf("%d", ans[i] + 1);printf("\n");exit(0);
}
void solveMin() {static pair <pair <int, int>, int> b[MAXN];for (int i = 1, j = 0; i <= n; i++) {b[++j] = make_pair(a[i][0], i);b[++j] = make_pair(a[i][1], i);}sort(b + 1, b + 2 * tot + 1);static int pre[MAXN], suf[MAXN];pre[0] = suf[2 * tot + 1] = INF;for (int i = 2 * tot; i >= 1; i--)suf[i] = min(suf[i + 1], b[i].first.second);for (int i = 1; i <= 2 * tot; i++)pre[i] = min(pre[i - 1], b[i].first.second);static int cnt[MAXN];priority_queue <int, vector <int>, greater <int>> Heap, Delt;for (int i = 1; i <= tot; i++)Heap.push(max(a[i][0].second, a[i][1].second));for (int i = 2 * tot, nxt; i >= 1; i = nxt) {nxt = i; while (nxt >= 1 && b[nxt].first.first == b[i].first.first) nxt--;while (!Heap.empty() && !Delt.empty() && Heap.top() == Delt.top()) {Heap.pop();Delt.pop();}int x = b[i].first.first, y = s.second - x;if (!Heap.empty()) chkmin(y, Heap.top());chkmin(y, suf[i + 1]);if (b[i].first.first <= pre[i] && y >= b[2 * tot].first.first && x + y >= s.first) foundAns(x, y);for (int j = nxt + 1; j <= i; j++) {if (++cnt[b[j].second] == 2) return;else Delt.push(max(a[b[j].second][0].second, a[b[j].second][1].second));}}
}
bool cmp(pair <pair <int, int>, int> x, pair <pair <int, int>, int> y) {return x.first.second > y.first.second;
}
void solveMax() {static pair <pair <int, int>, int> b[MAXN];for (int i = 1, j = 0; i <= n; i++) {b[++j] = make_pair(a[i][0], i);b[++j] = make_pair(a[i][1], i);}sort(b + 1, b + 2 * tot + 1, cmp);static int pre[MAXN], suf[MAXN];pre[0] = suf[2 * tot + 1] = 0;for (int i = 2 * tot; i >= 1; i--)suf[i] = max(suf[i + 1], b[i].first.first);for (int i = 1; i <= 2 * tot; i++)pre[i] = max(pre[i - 1], b[i].first.first);static int cnt[MAXN];priority_queue <int> Heap, Delt;for (int i = 1; i <= tot; i++)Heap.push(min(a[i][0].first, a[i][1].first));for (int i = 2 * tot, nxt; i >= 1; i = nxt) {nxt = i; while (nxt >= 1 && b[nxt].first.second == b[i].first.second) nxt--;while (!Heap.empty() && !Delt.empty() && Heap.top() == Delt.top()) {Heap.pop();Delt.pop();}int x = b[i].first.second, y = s.first - x;if (!Heap.empty()) chkmax(y, Heap.top());chkmax(y, suf[i + 1]);if (b[i].first.second >= pre[i] && y <= b[2 * tot].first.second && x + y <= s.second) foundAns(x, y);for (int j = nxt + 1; j <= i; j++) {if (++cnt[b[j].second] == 2) return;else Delt.push(min(a[b[j].second][0].first, a[b[j].second][1].first));}}
}
void dfs(int pos) {vis[pos] = true;points[tot].push_back(pos);chkmax(tmp[col[pos]].first, v[pos].first);chkmin(tmp[col[pos]].second, v[pos].second);for (auto x : e[pos])if (!vis[x]) {col[x] = !col[pos];dfs(x);} else if (col[pos] == col[x]) {puts("IMPOSSIBLE");exit(0);}
}
int main() {read(s.first), read(s.second), read(n), read(m);for (int i = 1; i <= n; i++)read(v[i].first), read(v[i].second);for (int i = 1; i <= m; i++) {int x, y; read(x), read(y);e[x].push_back(y);e[y].push_back(x);}for (int i = 1; i <= n; i++) {if (!vis[i]) {tmp[0] = tmp[1] = make_pair(0, INF);tot++, dfs(i);if (tmp[0].first > tmp[0].second || tmp[1].first > tmp[1].second) {puts("IMPOSSIBLE");return 0;}a[tot][0] = tmp[0];a[tot][1] = tmp[1];}}solveMin();solveMax();puts("IMPOSSIBLE");return 0;
}

Codeforces 547D Mike and Fish

首先,若对于解的存在性不加证明,则显然可以用有上下界的网络流解题,时间复杂度 O(NN)O(N\sqrt{N})O(NN​) 。

考虑解的存在性,首先假设图中每行每列均有偶数个点,那么,在这张二分图上每个联通块求欧拉回路即可构造出一组可行的解。

对于不满足每行每列均有偶数个点的情况,在度为奇数的点间两两连边,转化为以上情况即可。

时间复杂度 O(NLogN)O(NLogN)O(NLogN) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 4e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
vector <pair <int, int>> a[MAXN];
int n, m, x[MAXN], y[MAXN]; unsigned cur[MAXN];
set <pair <int, int>> path;
bool vis[MAXN];
void work(int pos, int fa) {for (unsigned &i = cur[pos]; i < a[pos].size(); i++)if (!vis[a[pos][i].second]) {vis[a[pos][i].second] = true;work(a[pos][i].first, pos);}if (fa) path.insert(make_pair(fa, pos));
}
int main() {n = 2e5, read(m);for (int i = 1; i <= m; i++) {read(x[i]), read(y[i]), y[i] += n;a[x[i]].emplace_back(y[i], i);a[y[i]].emplace_back(x[i], i);}vector <int> odd;for (int i = 1; i <= 2 * n; i++)if (a[i].size() & 1) odd.push_back(i);int tot = m;while (!odd.empty()) {int x = odd.back(); odd.pop_back();int y = odd.back(); odd.pop_back();a[x].emplace_back(y, ++tot);a[y].emplace_back(x, tot);}for (int i = 1; i <= 2 * n; i++)work(i, 0);for (int i = 1; i <= m; i++)if (path.count(make_pair(x[i], y[i]))) putchar('b');else putchar('r');putchar('\n');return 0;
}

Codeforces 547E Mike and Friends

离线询问,在后缀树上线段树合并即可。

时间复杂度 O(∑∣si∣LogN+QLogN)O(\sum|s_i|LogN+QLogN)O(∑∣si​∣LogN+QLogN) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 4e5 + 5;
const int MAXQ = 5e5 + 5;
const int MAXP = 8e6 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {write(x);puts("");
}
struct SegmentTreeMerging {struct Node {int lc, rc, sum;bool leaf;} a[MAXP];int size, n;void init(int x) {n = x;size = 0;}void update(int root) {a[root].sum = a[a[root].lc].sum + a[a[root].rc].sum;}void modify(int &root, int l, int r, int pos, int d) {if (root == 0) root = ++size;if (l == r) {a[root].sum += d;a[root].leaf = true;return;}int mid = (l + r) / 2;if (mid >= pos) modify(a[root].lc, l, mid, pos, d);else modify(a[root].rc, mid + 1, r, pos, d);update(root);}void modify(int &root, int val, int d) {modify(root, 1, n, val, d);}int merge(int x, int y) {if (x == 0 || y == 0) return x + y;if (a[x].leaf) {a[x].sum += a[y].sum;return x;}a[x].lc = merge(a[x].lc, a[y].lc);a[x].rc = merge(a[x].rc, a[y].rc);update(x);return x;}void join(int &to, int from) {to = merge(to, from);}int query(int root, int l, int r, int ql, int qr) {if (root == 0) return 0;if (l == ql && r == qr) return a[root].sum;int mid = (l + r) / 2, ans = 0;if (mid >= ql) ans += query(a[root].lc, l, mid, ql, min(mid, qr));if (mid + 1 <= qr) ans += query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);return ans;}int query(int root, int l, int r) {return query(root, 1, n, l, r);}
} ST;
struct SuffixAutomaton {struct Node {int child[26];int father, depth;} a[MAXN];vector <int> e[MAXN];vector <int> home[MAXN];vector <pair <int, int>> s[MAXN];int n, root, size, last;int newnode(int dep) {a[++size].depth = dep;return size;}void init() {size = 0;root = last = 0;}void extend(int ch) {int p = last, np;if (a[p].child[ch]) {int q = a[p].child[ch];if (a[p].depth + 1 == a[q].depth) np = q;else {np = newnode(a[p].depth + 1);memcpy(a[np].child, a[q].child, sizeof(a[q].child));a[np].father = a[q].father;a[q].father = np;while (a[p].child[ch] == q) {a[p].child[ch] = np;p = a[p].father;}}} else {np = newnode(a[p].depth + 1);while (a[p].child[ch] == 0) {a[p].child[ch] = np;p = a[p].father;}if (a[p].child[ch] == np) a[np].father = root;else {int q = a[p].child[ch];if (a[q].depth == a[p].depth + 1) a[np].father = q;else {int nq = newnode(a[p].depth + 1);memcpy(a[nq].child, a[q].child, sizeof(a[q].child));a[nq].father = a[q].father;a[q].father = a[np].father = nq;while (a[p].child[ch] == q) {a[p].child[ch] = nq;p = a[p].father;}}}}last = np;}void insert(char *s) {last = 0, n++;int len = strlen(s + 1);for (int i = 1; i <= len; i++) {extend(s[i] - 'a');home[n].push_back(last);}}int rt[MAXN], ans[MAXQ];vector <pair <pair <int, int>, int>> q[MAXN];void work(int pos) {for (auto x : s[pos])ST.modify(rt[pos], x.first, x.second);for (auto x : e[pos]) {work(x);ST.join(rt[pos], rt[x]);}for (auto x : q[pos])ans[x.second] = ST.query(rt[pos], x.first.first, x.first.second);}void solve(int m) {for (int i = 1; i <= size; i++)e[a[i].father].push_back(i);for (int i = 1; i <= n; i++)for (unsigned j = 0; j < home[i].size(); j++)s[home[i][j]].emplace_back(i, 1);work(0);for (int i = 1; i <= m; i++)writeln(ans[i]);}
} SAM;
char s[MAXN];
int main() {int n, m; read(n), read(m);SAM.init(), ST.init(n);for (int i = 1; i <= n; i++) {scanf("\n%s", s + 1);SAM.insert(s);}for (int i = 1; i <= m; i++) {int l, r, k; read(l), read(r), read(k);SAM.q[SAM.home[k].back()].emplace_back(make_pair(l, r), i);}SAM.solve(m);return 0;
}

Codeforces 549E Sasha Circle

建议参考 官方题解 阅读。

令 AAA 为圆内的点集, BBB 为圆外的点集。

可以认为,当存在一个圆,使得 AAA 中的点都在圆内或圆上, BBB 中的点都在圆外时,题目有解

若 AAA 中只有一个点,显然有解;若 ∣A∣>1|A|>1∣A∣>1 ,容易看出如果题目有解,那么肯定存在一个解使得 AAA 中至少有两个点在圆上。

考虑枚举 AAA 中的两个点,那么圆心一定在两点连线的中垂线上。对于其他 AAA 中的点和 BBB 中的点,每个点必须在圆内或者必须在圆外,那么会得到一个圆心坐标的可行区间。

由此,可以得到一个时间复杂度为 O((N2+M2)(N+M))O((N^2+M^2)(N+M))O((N2+M2)(N+M)) 的算法。

考虑转化问题。

将原平面作为 z=0z=0z=0 平面,将问题放到三维坐标系中讨论,画出抛物面 z=x2+y2z=x^2+y^2z=x2+y2 。

考虑抛物面和一个不与 z=0z=0z=0 垂直的平面相交得到的截面在 z=0z=0z=0 上的投影。

假设平面为 ax+by+z=cax+by+z=cax+by+z=c ,那么 x2+ax+y2+by=cx^2+ax+y^2+by=cx2+ax+y2+by=c ,

即 (x+a2)2+(y+b2)2=c+a2+b24(x+\frac{a}{2})^2+(y+\frac{b}{2})^2=c+\frac{a^2+b^2}{4}(x+2a​)2+(y+2b​)2=c+4a2+b2​ 。

通过方程可以看出投影一定是一个圆。

那么考虑将 z=0z=0z=0 上的点 (x,y,0)(x,y,0)(x,y,0) 映射到 (x,y,x2+y2)(x,y,x^2+y^2)(x,y,x2+y2) ,这是一一对应的。

也就是说 z=0z=0z=0 上的一个圆对应一个抛物面的截面,容易发现圆内的点一定在对应平面下方,圆外的点一定在对应平面上方,圆上的点一定在对应平面上。

于是问题转化为求一个平面,将抛物面上两点集分开,使得一点集在平面上方,另一点集在平面下方或平面上。

类比于平面上的情况,可以知道如果有解,则一定存在一个答案平面经过下方点集的上凸壳上两点,容易证明这两点一定在上凸壳上相邻,即对应上凸壳的一条边。

然后考虑上凸壳的边在 z=0z=0z=0 上的正投影,容易发现投影会是平面上对应凸包的一个剖分,当不存在四点共圆时,形成三角剖分,否则将其补成三角剖分。

由之前的讨论可知,需要枚举的点对就只有原凸包上的相邻点和剖分中的边的两端点。

考虑这个剖分的特征,回到凸壳上考虑,对于凸壳的每一个面,凸壳必然在其所在平面下面,对应到平面上就是凸包必然在三角剖分后每个三角形的外接圆内部。

所以只需要找到一个这样的剖分,需要枚举的边数就降到凸包的点数级别了。

考虑求出一个这样的剖分,考虑分治,在凸包上按逆(顺)时针讨论, solve(l,r)solve(l,r)solve(l,r) 表示将点 lll 到点 rrr 剖分。

将 (l,r)(l,r)(l,r) 这条边作为底边,找到一个点 k,(l<k<r)k,(l<k<r)k,(l<k<r) ,使得这三个点构成三角形的外接圆最大,可以证明这个三角形会包含整个凸包,然后递归做 solve(l,k),solve(k,r)solve(l,k),solve(k,r)solve(l,k),solve(k,r) 就好了。

时间复杂度 O((N+M)V23+NLogN+MLogM)O((N+M)V^{\frac{2}{3}}+NLogN+MLogM)O((N+M)V32​+NLogN+MLogM) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const double eps = 1e-8;
const double INF = 1e99;
const double pi = acos(-1);
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
struct point {double x, y; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, int b) {return (point) {a.x * b, a.y * b}; }
double operator * (point a, point b) {return a.x * b.y - a.y * b.x; }
double dot(point a, point b) {return a.x * b.x + a.y * b.y; }
double dist(point a, point b) {a = a - b;return sqrt(a.x * a.x + a.y * a.y);
}
bool onseg(point a, point b, point c) {return fabs(dist(a, b) - dist(a, c) - dist(b, c)) <= eps;
}
int n, m, top;
point p, a[MAXN], b[MAXN], c[MAXN];
vector <pair <int, int>> e;
bool cmp(point a, point b) {if ((a - p) * (b - p) == 0) return dist(a, p) < dist(b, p);else return (a - p) * (b - p) > 0;
}
void convexHull() {for (int i = 1; i <= n; i++)if (a[i].y < a[1].y || (a[i].y == a[1].y && a[i].x < a[1].x)) swap(a[i], a[1]);p = c[top = 1] = a[1];sort(a + 2, a + n + 1, cmp), a[n + 1] = p;for (int i = 2; i <= n + 1; i++) {while (top >= 2 + (i == n + 1) && (a[i] - c[top - 1]) * (c[top] - c[top - 1]) >= 0) top--;c[++top] = a[i];}
}
void work(int l, int r) {e.emplace_back(l, r);if (l == r - 1) return;double Max = -INF; int pos = 0;for (int i = l + 1; i <= r - 1; i++) {double ang = dot(c[r] - c[i], c[l] - c[i]) / ((c[r] - c[i]) * (c[l] - c[i]));if (ang > Max) {Max = ang;pos = i;}}work(l, pos);work(pos, r);
}
bool check(point l, point r) {pair <double, double> rng = make_pair(-INF, INF);for (int i = 1; i <= n; i++) {if (fabs((a[i] - l) * (r - l)) <= eps) {assert(onseg(l, r, a[i]));continue;}if ((a[i] - l) * (r - l) > 0) {double ang = dot(r - a[i], l - a[i]) / ((r - a[i]) * (l - a[i]));chkmax(rng.first, ang);} else {double ang = dot(l - a[i], r - a[i]) / ((l - a[i]) * (r - a[i]));chkmin(rng.second, -ang);}}for (int i = 1; i <= m; i++) {if (fabs((b[i] - l) * (r - l)) <= eps) {if (onseg(l, r, b[i])) return false;continue;}if ((b[i] - l) * (r - l) > 0) {double ang = dot(r - b[i], l - b[i]) / ((r - b[i]) * (l - b[i]));chkmin(rng.second, ang);} else {double ang = dot(l - b[i], r - b[i]) / ((l - b[i]) * (r - b[i]));chkmax(rng.first, -ang);}}return rng.first < rng.second - eps;
}
bool solve() {if (n == 1) return true;convexHull();e.clear(), work(1, top - 1);for (auto x : e)if (check(c[x.first], c[x.second])) return true;return false;
}
int main() {read(n), read(m);for (int i = 1; i <= n; i++)read(a[i].x), read(a[i].y);for (int i = 1; i <= m; i++)read(b[i].x), read(b[i].y);if (solve()) {puts("YES");return 0;}swap(n, m);swap(a, b);if (solve()) {puts("YES");return 0;}puts("NO");return 0;
}

Codeforces 553E Kyoya and Train

考虑一个暴力 dp ,记 dpi,jdp_{i,j}dpi,j​ 表示在点 iii 处,时刻 jjj 最优决策的期望花费。

则有
dpi,j={x+dist(i,N)j>T0i=N,j≤TMini⇒e∈E{costi,e+∑k=1tpi,e,k∗dpe,j+k}i≠N,j≤Tdp_{i,j}=\left\{\begin{array}{rcl}x+dist(i,N)&&{j>T}\\0&&{i=N,j≤T}\\Min_{i\Rightarrow e\in E}\{cost_{i,e}+\sum_{k=1}^{t}p_{i,e,k}*dp_{e,j+k}\}&&{i\ne N,j≤T}\end{array} \right.dpi,j​=⎩⎨⎧​x+dist(i,N)0Mini⇒e∈E​{costi,e​+∑k=1t​pi,e,k​∗dpe,j+k​}​​j>Ti=N,j≤Ti​=N,j≤T​

我们希望求出 dp1,0dp_{1,0}dp1,0​ 。

用分治 FFT 优化该 dp 即可。

具体来说,我们可以轻松地得到 dp∗,j(j>T)dp_{*,j}\ (j>T)dp∗,j​ (j>T) ,也可以快速地计算出 dp∗,j(j>T)dp_{*,j}\ (j>T)dp∗,j​ (j>T) 对后续 dp 的影响,即 transi,e,j=∑k=1t[j+k>T]∗pi,e,k∗dpe,j+ktrans_{i,e,j}=\sum_{k=1}^{t}[j+k>T]*p_{i,e,k}*dp_{e,j+k}transi,e,j​=∑k=1t​[j+k>T]∗pi,e,k​∗dpe,j+k​ 。

那么考虑分治,对于时刻区间 [l,r][l,r][l,r] ,取 mid=⌊l+r2⌋mid=\lfloor\frac{l+r}{2}\rfloormid=⌊2l+r​⌋ ,首先计算出时刻区间 [mid+1,r][mid+1,r][mid+1,r] 的 dp 值,然后用 FFT 计算时刻区间 [mid+1,r][mid+1,r][mid+1,r] 的 dp 值对时刻区间 [l,mid][l,mid][l,mid] 的影响,即 transi,e,j=∑k=1t[mid<j+k≤r]∗pi,e,k∗dpe,j+ktrans_{i,e,j}=\sum_{k=1}^{t}[mid<j+k≤r]*p_{i,e,k}*dp_{e,j+k}transi,e,j​=∑k=1t​[mid<j+k≤r]∗pi,e,k​∗dpe,j+k​ ,最后递归计算时刻区间 [l,mid][l,mid][l,mid] 的 dp 值。

时间复杂度 O(N3+MTLog2T)O(N^3+MTLog^2T)O(N3+MTLog2T) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 55;
const int MAXM = 32768;
const double INF = 1e18;
const double pi = acos(-1);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {write(x);puts("");
}
struct point {double x, y; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, point b) {return (point) {a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x}; }
point operator / (point a, double x) {return (point) {a.x / x, a.y / x}; }
int n, m, t, fine;
vector <pair <int, int> > e;
double dist[MAXN][MAXN], edge[MAXN][MAXN];
vector <double> dp[MAXN], trans[MAXN][MAXN], p[MAXN][MAXN];
int N, Log, home[MAXM]; point a[MAXM], b[MAXM], c[MAXM];
void FFT(point *a, int mode) {for (int i = 0; i < N; i++)if (home[i] > i) swap(a[i], a[home[i]]);for (int len = 2; len <= N; len <<= 1) {point delta = (point) {cos(2 * pi / len * mode), sin(2 * pi / len * mode)};for (int i = 0; i < N; i += len) {point now = (point) {1, 0};for (int j = i, k = i + len / 2; k < i + len; j++, k++) {point tmp = a[j], tnp = a[k];a[j] = tmp + tnp * now;a[k] = tmp - tnp * now;now = now * delta;}}}if (mode == -1) {for (int i = 0; i < N; i++)a[i] = a[i] / N;}
}
void transfer(int l, int mid, int r, vector <double> &dp, vector <double> &p, vector <double> &res) {N = 1, Log = 0;while (N <= (r - l) + (r - mid)) {N <<= 1;Log++;}for (int i = 0; i < N; i++) {int tmp = i, res = 0;for (int j = 1; j <= Log; j++) {res <<= 1;res += tmp & 1;tmp >>= 1;}home[i] = res;}for (int i = 0; i < N; i++)a[i] = b[i] = (point) {0, 0};for (int i = mid + 1; i <= r; i++)a[r - i].x = dp[i];for (int i = 0; i <= r - l; i++)b[i].x = p[i];FFT(a, 1), FFT(b, 1);for (int i = 0; i < N; i++)c[i] = a[i] * b[i];FFT(c, -1);for (int i = l; i <= mid; i++)res[i] += c[r - i].x;
}
void work(int l, int r) {if (l == r) {for (int i = 1; i <= n - 1; i++)dp[i][l] = INF;for (auto x : e) {int i = x.first, j = x.second;chkmin(dp[i][l], trans[i][j][l] + edge[i][j]);}return;}int mid = (l + r) / 2;work(mid + 1, r);for (auto x : e) {int i = x.first, j = x.second;transfer(l, mid, r, dp[j], p[i][j], trans[i][j]);}work(l, mid);
}
int main() {read(n), read(m), read(t), read(fine);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)if (i == j) dist[i][j] = 0;else dist[i][j] = INF;for (int i = 1; i <= n; i++)dp[i].resize(t + 1);for (int i = 1; i <= m; i++) {int x, y, z;read(x), read(y), read(z);if (dist[x][y] == INF) {e.emplace_back(x, y);edge[x][y] = z;}chkmin(dist[x][y], z * 1.0);chkmin(edge[x][y], z * 1.0);p[x][y].push_back(0);trans[x][y].resize(t + 1);for (int j = 1; j <= t; j++) {int val; read(val);p[x][y].push_back(val * 0.00001);}}for (int k = 1; k <= n; k++)for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)chkmin(dist[i][j], dist[i][k] + dist[k][j]);for (auto x : e) {int i = x.first, j = x.second;double res = 1;for (int k = t; k >= 0; k--) {res -= p[i][j][t - k];trans[i][j][k] = res * (dist[j][n] + fine);}}work(0, t);printf("%.10lf\n", dp[1][0]);return 0;
}

Codeforces 555E Case of Computer Network

首先,可以将树上的边双连通分量缩成点,因为显然可以定向使得边双连通分量强连通。

此后,问题变成了森林上的问题,树上差分解决即可。

时间复杂度 O(NLogN+M+QLogN)O(NLogN+M+QLogN)O(NLogN+M+QLogN) 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXLOG = 20;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
vector <pair <int, int>> a[MAXN];
int n, m, q, top, tot, Stack[MAXN], belong[MAXN];
int timer, x[MAXN], y[MAXN], dfn[MAXN], low[MAXN], col[MAXN];
void work(int pos, int fa, int c) {Stack[++top] = pos, col[pos] = c;dfn[pos] = low[pos] = ++timer;for (auto x : a[pos])if (dfn[x.first] == 0) {work(x.first, x.second, c);chkmin(low[pos], low[x.first]);} else if (x.second != fa) chkmin(low[pos], dfn[x.first]);if (dfn[pos] == low[pos]) {int tmp = Stack[top--];belong[tmp] = ++tot;while (tmp != pos) {tmp = Stack[top--];belong[tmp] = tot;}}
}
vector <int> b[MAXN];
int depth[MAXN], father[MAXN][MAXLOG];
void dfs(int pos, int fa) {father[pos][0] = fa;depth[pos] = depth[fa] + 1;for (int i = 1; i < MAXLOG; i++)father[pos][i] = father[father[pos][i - 1]][i - 1];for (unsigned i = 0; i < b[pos].size(); i++)if (b[pos][i] != fa) dfs(b[pos][i], pos);
}
int lca(int x, int y) {if (depth[x] < depth[y]) swap(x, y);for (int i = MAXLOG - 1; i >= 0; i--)if (depth[father[x][i]] >= depth[y]) x = father[x][i];if (x == y) return x;for (int i = MAXLOG - 1; i >= 0; i--)if (father[x][i] != father[y][i]) {x = father[x][i];y = father[y][i];}return father[x][0];
}
bool vis[MAXN];
int sum[MAXN][2];
void getans(int pos, int fa) {vis[pos] = true;for (auto x : b[pos])if (x != fa) {getans(x, pos);sum[pos][0] += sum[x][0];sum[pos][1] += sum[x][1];}if (sum[pos][0] && sum[pos][1]) {puts("No");exit(0);}
}
int main() {read(n), read(m), read(q);for (int i = 1; i <= m; i++) {read(x[i]), read(y[i]);a[x[i]].emplace_back(y[i], i);a[y[i]].emplace_back(x[i], i);}for (int i = 1, j = 0; i <= n; i++)if (dfn[i] == 0) work(i, 0, ++j);for (int i = 1; i <= m; i++)if (belong[x[i]] != belong[y[i]]) {b[belong[x[i]]].push_back(belong[y[i]]);b[belong[y[i]]].push_back(belong[x[i]]);}for (int i = 1; i <= tot; i++)if (depth[i] == 0) dfs(i, 0);for (int i = 1; i <= q; i++) {int x, y; read(x), read(y);if (col[x] != col[y]) {puts("No");return 0;}x = belong[x], y = belong[y];int z = lca(x, y);sum[x][0]++, sum[z][0]--;sum[y][1]++, sum[z][1]--;}for (int i = 1; i <= tot; i++)if (!vis[i]) getans(i, 0);puts("Yes");return 0;
}

Codeforces 559E Gerald and Path

考虑按照从左向右的顺序 DP 。

由于可能的分界点数是 O(N)O(N)O(N) 的,可以记 dpidp_idpi​ 表示 axa_xax​ 在第 iii 个分界点 posipos_iposi​ 左侧的灯塔照到的最右侧的位置是第 iii 个分界点时,最优的覆盖长度。

转移时考虑 O(N2)O(N^2)O(N2) 枚举其右侧的下一个被完全覆盖的区间 [posj,posk][pos_j,pos_k][posj​,posk​] ,判断其是否能够被完全覆盖,若可以,则将 dpi+posk−posjdp_{i}+pos_k-pos_jdpi​+posk​−posj​ 转移至 dpkdp_kdpk​ 。

那么,剩余的问题就在于判断区间 [posj,posk][pos_j,pos_k][posj​,posk​] 是否能够被完全覆盖。

枚举枚举左起第一盏照到 posjpos_jposj​ 的灯,其右侧的灯都应照向右侧,由此,可以将其递归为一个子问题。

以下代码的时间复杂度为 O(N4)O(N^4)O(N4) ,可简单优化至 O(N3)O(N^3)O(N3) ,但实际运行迅速。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int INF  = 5e8;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f;
}
pair <int, int> a[MAXN];
unordered_map <ll, bool> mp;
int n, dp[MAXN][2], c[MAXN][2][MAXN][2];
bool solve(int l, int r) {if (l >= r) return true;ll tmp = 1ll * INF * l + r;if (mp.count(tmp)) return mp[tmp];bool &ans = mp[tmp];ans = false; int Max = l;for (int i = 1; i <= n && !ans; i++)if (a[i].first > l && a[i].first < r) {if (a[i].first - a[i].second <= l) {int tmp = max(Max, a[i].first);for (int j = i + 1; j <= n && a[j].first <= tmp; j++)chkmax(tmp, a[j].first + a[j].second);ans |= solve(tmp, r);}chkmax(Max, a[i].first + a[i].second);}return ans;
}
int coef(int l, int tl, int r, int tr) {if (c[l][tl][r][tr] != -INF - 1) return c[l][tl][r][tr];int &ans = c[l][tl][r][tr]; ans = -INF;int bl = a[l].first - (tl == 0) * a[l].second, cl = a[l].first + (tl == 1) * a[l].second;int br = a[r].first - (tr == 0) * a[r].second, cr = a[r].first + (tr == 1) * a[r].second;if (bl > br || cl > cr || (l == r && tl != tr)) return ans;for (int i = 1; i <= n; i++)if (a[i].first >= bl && a[i].first <= cl && i != l) chkmax(cl, a[i].first + a[i].second);for (int i = n; i >= 1; i--)if (a[i].first <= cr && a[i].first >= br && i != r) chkmin(br, a[i].first - a[i].second);if (solve(cl, br)) return ans = cr - bl;return ans;
}
int main() {read(n);a[0] = make_pair(-INF, 0);for (int i = 1; i <= n; i++)read(a[i].first), read(a[i].second);sort(a + 1, a + n + 1);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)c[i][0][j][0] = c[i][0][j][1] = c[i][1][j][0] = c[i][1][j][1] = -INF - 1;for (int i = 0; i <= n; i++) {int tmp = dp[i][0];for (int j = i + 1; j <= n; j++)for (int k = i + 1; k <= n; k++) {if (a[j].first > a[i].first) chkmax(dp[k][0], tmp + coef(j, 1, k, 0));if (a[j].first > a[i].first) chkmax(dp[k][1], tmp + coef(j, 1, k, 1));if (a[j].first - a[j].second > a[i].first) chkmax(dp[k][0], tmp + coef(j, 0, k, 0));if (a[j].first - a[j].second > a[i].first) chkmax(dp[k][1], tmp + coef(j, 0, k, 1));}tmp = dp[i][1];for (int j = i + 1; j <= n; j++)for (int k = i + 1; k <= n; k++) {if (a[j].first > a[i].first + a[i].second) chkmax(dp[k][0], tmp + coef(j, 1, k, 0));if (a[j].first > a[i].first + a[i].second) chkmax(dp[k][1], tmp + coef(j, 1, k, 1));if (a[j].first - a[j].second > a[i].first + a[i].second) chkmax(dp[k][0], tmp + coef(j, 0, k, 0));if (a[j].first - a[j].second > a[i].first + a[i].second) chkmax(dp[k][1], tmp + coef(j, 0, k, 1));}}int ans = 0;for (int i = 1; i <= n; i++) {chkmax(ans, dp[i][0]);chkmax(ans, dp[i][1]);}cout << ans << endl;return 0;
}

【集训队作业】IOI 2020 集训队作业 试题泛做 8相关推荐

  1. 【集训队作业】IOI 2020 集训队作业 试题泛做 13

    Codeforces 679E Bear and Bad Powers of 42 不难发现数列中的元素不可能达到很大,我们只需要考虑 424242 的前若干个幂. 考虑没有赋值操作的做法,则可用线段 ...

  2. 论弱逼的自我修养——2014集训队CF试题泛做

    为了增长姿势水平提高思考能力,我决定跟着神犇膜一膜2014的集训队作业: 似乎大多数是CF上的DE题,应该比较有含金量(然而博主是个div2连D都没做上过的**): 感觉不久就会弃坑吧,大家来猜猜窝能 ...

  3. Shoi2017试题泛做

    一口气做完六个省的省选(误) Day1 [Shoi2017]期末考试 枚举最大的天数,然后代价贪心地O(1)计算. 1 #include <cstdio> 2 #include <a ...

  4. 2020年电力电缆试题及答案及电力电缆考试平台

    题库来源:安全生产模拟考试一点通公众号小程序 2020年电力电缆试题及答案及电力电缆考试平台,包含电力电缆试题及答案答案和解析及电力电缆考试平台练习.由安全生产模拟考试一点通公众号结合国家电力电缆考试 ...

  5. IOI 2020落幕,中国队团体成绩第一,美籍华裔选手拿下唯一满分

    边策 贾浩楠 发自 凹非寺  量子位 报道 | 公众号 QbitAI 2020年国际信息学奥赛(IOI 2020)完成了第二日比赛,四名中国队选手皆进入前十,分列3~7名,团队总成绩第一! 罗煜翔:来 ...

  6. html大作业_杜绝家长作业 关键是如何监督

    风评 杜绝家长作业 关键是如何监督 中国青年报 ( 2020年11月19日 04 版) 晨雾 / 转帖 张学炬 近日,武汉市教育局发出<关于开展杜绝"家长作业"进一步减轻中小 ...

  7. HTML期末作业课程设计大作业~环境保护学生网页设计作业源码(HTML+CSS)

    HTML期末大作业~基于HTML+CSS环境保护学生网页设计 临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大?HTML网页作业无从下手?网页要求的总数量太多?没有合适的模板?等等 ...

  8. 外部仓库_仓库主要作业流程和WMS作业优化方案

    仓库在人们眼中一直是低效.高成本的地方,即便是增加人手也很难做好仓库管理.那么我们应该采取哪些方式来管理,才能做到降本增效呢? 首先我们需要先了解仓库主要作业流程及在作业中存在的痛点. 1 入库流程 ...

  9. python实验报告代写_TensorFlow作业代写、代做Python程序语言作业、代写github课程作业、Python实验作业代写...

    TensorFlow作业代写.代做Python程序语言作业.代写github课程作业.Python实验作业代写 日期:2019-07-10 10:34 Python Practical Examine ...

  10. 代写php代码作业,代写phpmyadmin留学生作业、代做SQL语言作业、SQL程序设计作业调试、代做PHP script作业...

    代写phpmyadmin留学生作业.代做SQL语言作业.SQL程序设计作业调试.代做PHP script作业 日期:2019-04-20 01:17 Overview:In this assignme ...

最新文章

  1. 想成为一个数据科学家却不知道从何下手?这份路线图带你打开数据科学大门!...
  2. SharePoint 沙盒解决方案 VS 场解决方案
  3. 文巾解题 981. 基于时间的键值存储
  4. Jquery赋值和取值input,combobox,numberbox........
  5. Arduino--ESP8266物联网WIFI模块(贝壳物联)--数据上传服务器(单数据接口)
  6. react学习(73)--子组件this
  7. 利用moviepy库制作好用的MP4、mov、mav、avi等视频类型转换gif图片的工具
  8. Jenkins 学习总结(9)—— Jenkins 有哪些替代方案?
  9. Kotlin 1.2 有哪些新特性
  10. shell练习DAY14
  11. 基于DEAP库的python进化算法-5.遗传算法求解TSP问题的改进
  12. h5调用摄像头 android,H5 使用移动端摄像头
  13. 尚学堂马士兵Oracle教程笔记
  14. python selenium清除缓存,Selenium Python:无法清除chrome浏览器缓存
  15. Hexo主题next中添加天气插件(心知天气)
  16. gdb: warning Can‘t open file /usr/lib/libstdc++.so.6.0.19 during file-backed mapping note processing
  17. 软件开发工作量及费用量化评估方法在金融行业的应用
  18. 应用密码学第一章绪论笔记
  19. 多平台大型文件系统比较
  20. xgs芯片_IBM Security XGS和网络访问控制

热门文章

  1. IIS6.0相关漏洞复现
  2. kettle连接ACCESS数据库
  3. ADB常用命令及其用法大全
  4. 最新的SAS SID 2023可用至2023年1月SAS 9.4 SID续订更新sas sid 2022服务器通用版server
  5. 易用性软件测试用例,易用性测试用例集
  6. mysql数据库旅游管理系统_JSP+MySQL基于ssm的旅游管理系统
  7. 基于SSM和Vue的旅游网和旅游管理系统
  8. 【VC ++6.0】VC++6.0的安装
  9. android 空格的转义字符,Android 常用转义字符
  10. Python炸弹人小游戏源代码