「2019纪中集训Day2」解题报告
T1、Attack
这道题时间给的比较多 (可能是以前评测机比较弱),\(O(nm)\) 就可以过。
\(Sol\) 给了分块加划分树的做法,不是很会,但是这道题可以用很多数据结构来做;
我写了整体二分+树套树 (还没调出来),整体二分+ \(cdq\) 也行,代码应该是最短的。
只给出 \(O(nm)\) 的代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }
const int N = 6e4 + 5;
struct node {
int x, y, z;
} a[N];
int n, m, id[N], rnk[N];
inline bool cmp(const int &i, const int &j) {
return a[i].z < a[j].z;
}
char s[11];
int main() {
// freopen("in", "r", stdin);
n = in(), m = in();
for (int i = 1; i <= n; ++i)
a[i] = (node){in(), in(), in()}, id[i] = i;
std::sort(id + 1, id + 1 + n, cmp);
for (int i = 1; i <= n; ++i)
rnk[id[i]] = i;
while (m--) {
scanf(" %s", s);
if (s[0] == 'S') {
int u = in() + 1, v = in() + 1;
std::swap(a[u].z, a[v].z);
std::swap(id[rnk[u]], id[rnk[v]]);
std::swap(rnk[u], rnk[v]);
} else {
int x = in(), y = in(), p = in(), s = in(), k = in();
if (!k) {
puts("It doesn't exist.");
continue;
}
if (x > p)
std::swap(x, p);
if (y > s)
std::swap(y, s);
for (int i = 1; i <= n; ++i) {
if (a[id[i]].x >= x && a[id[i]].y >= y && a[id[i]].x <= p && a[id[i]].y <= s)
--k;
if (!k) {
printf("%d\n", a[id[i]].z);
break;
}
}
if (k)
puts("It doesn't exist.");
}
}
return 0;
}
T2、Contra
\(Sol\):
\(f[i + 1][min(j + 1,Q)][\min(k + 1, R)] += p \times f[i][j][k]\) (第 \(i +1\) 轮通过);
\(f[i + 1][j - 1][0] += (1 - p) \times f[i][j][k], (j > 1)\) (第 \(i + 1\) 轮不通过);
因为期望的线性性,可以单独计算每一轮游戏的贡献, \(ans = \sum {f[i][j][k] \times p \times \min(k + 1, R)}\),其中 \(f[i][j][k]\) 为合法状态。
因为合法状态数最多不超过 \(\frac{Q * (Q - 1)}{2} + R + 1\),所以可以矩阵优化。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef double db;
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }
const int M = 45;
const db eps = 4e-8;
int n, r, q, s, nn;
struct matrix {
db a[M][M];
matrix(db t = 0) {
memset(a, 0, sizeof(a));
if (t > 0)
for (int i = 1; i <= nn; ++i)
a[i][i] = t;
}
inline db* operator [] (int x) {
return a[x];
}
inline matrix operator * (matrix &b) const {
matrix ret;
for (int k = 1; k <= nn; ++k)
for (int i = 1; i <= nn; ++i)
for (int j = 1; j <= nn; ++j)
ret[i][j] += a[i][k] * b[k][j];
return ret;
}
} ;
matrix qpow(matrix base, int b) {
matrix ret(1);
for (; b; b >>= 1, base = base * base)
if (b & 1)
ret = ret * base;
return ret;
}
int state[7][21], cnt;
db calc(db p) {
matrix a(0), trans(0);
a[1][state[q][1]] = p, a[1][state[q - 1][0]] = 1 - p, a[1][nn] = p * std::min(1, r);
trans[nn][nn] = 1;
for (int j = 1; j <= q; ++j) {
for (int k = 0; k <= r; ++k) {
if (j != q && k >= j)
continue;
int x = std::min(q, j + 1), y = std::min(r, k + 1);
trans[state[j][k]][state[x][y]] = p;
trans[state[j][k]][state[j - 1][0]] = 1 - p;
trans[state[j][k]][nn] = p * std::min(r, k + 1);
// printf("%lf\n", trans[state[j][k]][nn]);
}
}
trans = qpow(trans, n - 1);
a = a * trans;
return a[1][nn];
}
int main() {
// freopen("in", "r", stdin);
n = in(), r = in(), q = in(), s = in();
for (int i = 1; i <= q; ++i)
for (int j = 0; j <= r; ++j)
if ((i == q) || (j < i))
state[i][j] = ++nn;
++nn;
if (calc(1) - s < eps) {
puts("Impossible.");
return 0;
}
db l = 0, r = 1, mid;
while (r - l > eps) {
mid = (l + r) / 2;
if (calc(mid) > s)
r = mid;
else
l = mid + eps;
}
printf("%lf\n", l);
return 0;
}
T3、Bomb
最大值分类讨论,最小值分治即可 (也可以选择随机化分治)。