感觉Day2比2013还恶心……后来看了清华爷zzq的讲解,才搞出T2。
T1 cheese
模拟题。把可以互相到达的球连边后,用bfs或并查集判断是否连通。
注意细(keng)节(dian):在极端情况下,两点之间的距离会达到
1.2∗1019
(爆long long),所以要用unsigned long long或double。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1005; const double eps = 1e-8;
int n, h, r, X[N], Y[N], Z[N], fa[N]; double DIS;
inline int cx(const int &x) {
if (fa[x] != x) fa[x] = cx(fa[x]);
return fa[x];
}
inline void zm(const int &x, const int &y) {
int ix = cx(x), iy = cx(y);
if (ix != iy) fa[iy] = ix;
}
inline bool check(const int &i, const int &j) {
if (X[i] - X[j] > (r << 1) || Y[i] - Y[j] > (r << 1) ||
Z[i] - Z[j] > (r << 1)) return 0;
double dis = 1.0 * (X[i] - X[j]) * (X[i] - X[j]) + 1.0 *
(Y[i] - Y[j]) * (Y[i] - Y[j]) + 1.0 * (Z[i] - Z[j]) * (Z[i] - Z[j]);
return abs(DIS - dis) <= eps || dis < DIS;
}
void work() {
int i, j; n = read(); h = read(); r = read(); DIS = 4.0 * r * r;
for (i = 1; i <= n + 2; i++) fa[i] = i;
for (i = 1; i <= n; i++) X[i] = read(), Y[i] = read(), Z[i] = read();
for (i = 1; i < n; i++) for (j = i + 1; j <= n; j++)
if (check(i, j)) zm(i, j);
for (i = 1; i <= n; i++) {
if (Z[i] <= r) zm(n + 1, i);
if (Z[i] >= h - r) zm(i, n + 2);
}
puts(cx(n + 1) == cx(n + 2) ? "Yes" : "No");
}
int main() {
//freopen("cheese.in", "r", stdin);
//freopen("cheese.out", "w", stdout);
int T = read();
while (T--) work();
return 0;
}
T2 treasure
看到
12
的数据范围,容易想到状压DP,可以建立如下模型:
f[u][dep][S]
表示
u
的深度为
容易推出转移:
其中
val<u,v>
为
<u,v>
<script type="math/tex" id="MathJax-Element-11">
</script>的边权。枚举子集,实现即为:
for (i = (S - 1) & S; i; i = (i - 1) & S);
这时候复杂度为
O(3nn3)
,考虑优化,可以发现,枚举
v
特别浪费时间。所以容易想到,把
g[u][dep][S]=min(f[v][dep][S]+val<u,v>∗(dep−1))
这时候,转移方程优化为:
f[u][dep][S]=minS′⊆S,u∉S(f[u][dep[S−S′]+g[u][dep+1][S])
复杂度
O(3nn2)
。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 16, C = (1 << 12) + 5, INF = 0x3f3f3f3f;
int n, m, G[N][N], f[N][N][C], g[N][N][C];
void dfs(int u, int dep, int S) {
if (f[u][dep][S] != -1) return;
if (S == (1 << u - 1)) return (void) (f[u][dep][S] = g[u][dep][S] = 0);
int i, j; f[u][dep][S] = g[u][dep][S] = INF;
for (j = (S - 1) & S; j; j = (j - 1) & S) {
if ((j >> u - 1) & 1) continue; dfs(u, dep, S - j); dfs(u, dep + 1, j);
f[u][dep][S] = min(f[u][dep][S], f[u][dep][S - j] + g[u][dep + 1][j]);
}
for (i = 1; i <= n; i++) {
if (!((S >> i - 1) & 1) || G[u][i] == INF) continue;
dfs(i, dep, S);
g[u][dep][S] = min(g[u][dep][S], f[i][dep][S] + G[u][i] * (dep - 1));
}
}
int main() {
//freopen("treasure.in", "r", stdin);
//freopen("treasure.out", "w", stdout);
memset(G, INF, sizeof(G)); memset(f, -1, sizeof(f));
int i, j, k, x, y, z, ans = INF; n = read(); m = read();
for (i = 1; i <= m; i++) {
x = read(); y = read(); z = read();
G[x][y] = min(G[x][y], z);
G[y][x] = min(G[y][x], z);
}
for (i = 1; i <= n; i++) ans =
min(ans, (dfs(i, 1, (1 << n) - 1), f[i][1][(1 << n) - 1]));
cout << ans << endl;
return 0;
}
T3 phalanx
好像是NOIP有史以来第一道数据结构题。
蒟蒻用的是Splay的做法,即用
n
棵Splay维护每一行的前
考虑到空间问题,对于前
据说标算是树状数组。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 3e6 + 5;
int n, m, q, T, fa[N], lc[N], rc[N], rt[N]; ll sze[N], L[N], R[N];
int which(int x) {return rc[fa[x]] == x;}
void upt(int x) {
sze[x] = R[x] - L[x] + 1;
if (lc[x]) sze[x] += sze[lc[x]];
if (rc[x]) sze[x] += sze[rc[x]];
}
void rotate(int x) {
int y = fa[x], z = fa[y], b = lc[y] == x ? rc[x] : lc[x];
if (z) (lc[z] == y ? lc[z] : rc[z]) = x;
fa[x] = z; fa[y] = x; if (b) fa[b] = y;
if (lc[y] == x) rc[x] = y, lc[y] = b;
else lc[x] = y, rc[y] = b; upt(y); upt(x);
}
void splay(int x, int tar, int r) {
while (fa[x] != tar) {
if (fa[fa[x]] != tar) {
if (which(x) == which(fa[x])) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
if (!tar) rt[r] = x;
}
void BuildRow(int row) {
int i, x = ++T; L[rt[row] = x] = 1ll * (row - 1) * m + 1;
R[x] = 1ll * row * m - 1; fa[lc[x] = ++T] = x; fa[rc[x] = ++T] = x;
sze[lc[x]] = sze[rc[x]] = 1; L[lc[x]] = R[lc[x]] = 1ll * (row - 1) * m;
L[rc[x]] = R[rc[x]] = 1ll * row * m; upt(x);
}
int BuildLast(int l, int r) {
int mid = l + r >> 1, x = ++T;
if (l == 0 && r == n + 1) rt[n + 1] = x;
if (l < mid) fa[lc[x] = BuildLast(l, mid - 1)] = x;
if (mid < r) fa[rc[x] = BuildLast(mid + 1, r)] = x;
L[x] = R[x] = 1ll * mid * m; return upt(x), x;
}
void build() {
int i; for (i = 1; i <= n; i++) BuildRow(i);
BuildLast(0, n + 1);
}
void DivLeft(int x, ll mid) {
int y = lc[x], z = ++T;
fa[lc[x] = z] = x; if (y) fa[lc[z] = y] = z;
L[z] = L[x]; L[x] = mid + 1; R[z] = mid;
upt(z); upt(x);
}
void DivRight(int x, ll mid) {
int y = rc[x], z = ++T;
fa[rc[x] = z] = x; if (y) fa[rc[z] = y] = z;
R[z] = R[x]; R[x] = mid - 1; L[z] = mid;
upt(z); upt(x);
}
void Divide(int x, ll mid) {
ll tl = L[x], tr = R[x];
if (tl < mid) DivLeft(x, mid - 1);
if (mid < tr) DivRight(x, mid + 1);
}
void Find(int wh, ll rk, int tar) {
int x = rt[wh]; while (x) {
ll tmp = lc[x] ? sze[lc[x]] : 0;
if (rk > tmp && rk <= tmp + (R[x] - L[x] + 1))
return splay(x, tar, wh), Divide(x, L[x] + rk - tmp - 1);
else if (rk <= tmp) x = lc[x];
else rk -= tmp + (R[x] - L[x] + 1), x = rc[x];
}
}
ll query(int x, int y) {
ll res; Find(x, y, 0); Find(x, y + 2, rt[x]);
int u = rt[x], v = rc[u], w = lc[v]; res = L[w];
fa[w] = lc[v] = 0; upt(v); upt(u); Find(n + 1, x, 0);
Find(n + 1, x + 2, rt[n + 1]); int r = rt[n + 1], s = rc[r], t = lc[s];
fa[t] = lc[s] = 0; upt(s); upt(r);
Find(x, m - 1, 0); Find(x, m, rt[x]);
fa[lc[rc[rt[x]]] = t] = rc[rt[x]]; upt(rc[rt[x]]); upt(rt[x]);
Find(n + 1, n, 0); Find(n + 1, n + 1, rt[n + 1]);
fa[lc[rc[rt[n + 1]]] = w] = rc[rt[n + 1]];
return upt(rc[rt[n + 1]]), upt(rt[n + 1]), res;
}
ll ask(int x) {
ll res; Find(n + 1, x, 0); Find(n + 1, x + 2, rt[n + 1]);
int u = rt[n + 1], v = rc[u], w = lc[v]; res = L[w];
fa[w] = lc[v] = 0; upt(v); upt(u);
Find(n + 1, n, 0); Find(n + 1, n + 1, rt[n + 1]);
fa[lc[rc[rt[n + 1]]] = w] = rc[rt[n + 1]];
return upt(rc[rt[n + 1]]), upt(rt[n + 1]), res;
}
int main() {
//freopen("phalanx.in", "r", stdin);
//freopen("phalanx.out", "w", stdout);
int x, y; n = read(); m = read(); q = read(); build();
while (q--) {
x = read(); y = read();
printf("%lld\n", y == m ? ask(x) : query(x, y));
}
return 0;
}