# T1、迷宫

1、修改某个格子的类型；
2、查询从 $(a, b)$ 到 $(c, d)$ 的最短路，不可达输出 $-1$。 (保证后者在前者右边)。

## $Source$：

#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;
}

const int N = 2e5 + 5;

int n, m, q, mp[7][N];

template<typename T>inline void chk_min(T &_, T __) {
_ = !~_ ? __ : (_ < __ ? _ : __);
}
struct node {
int a[6][6];
node () {
memset(a, -1, sizeof(a));
}
inline int* operator [] (const int x) {
return a[x];
}
inline node operator + (node b) const {
node ret;
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
if (~a[i][k])
for (int j = 1; j <= n; ++j)
if (~b[k][j])
chk_min(ret[i][j], a[i][k] + b[k][j] + 1);
return ret;
}
} ;
struct segment_tree {
node t[N << 2];
void init(int x, int p) {
for (int i = 1, j; i <= n; ++i) {
for (j = i; j <= n && mp[j][x]; ++j)
t[p][i][j] = j - i;
for (; j <= n; ++j)
t[p][i][j] = -1;
for (j = i; j && mp[j][x]; --j)
t[p][i][j] = i - j;
for (; j; --j)
t[p][i][j] = -1;
}
}
inline void push_up(int p) {
t[p] = t[p << 1] + t[p << 1 | 1];
}
void build(int tl, int tr, int p) {
if (tl == tr)
return init(tl, p);
int mid = (tl + tr) >> 1;
build(tl, mid, p << 1), build(mid + 1, tr, p << 1 | 1);
push_up(p);
}
void modify(int pos, int tl, int tr, int p) {
if (tl == tr)
return init(tl, p);
int mid = (tl + tr) >> 1;
if (mid >= pos)
modify(pos, tl, mid, p << 1);
else
modify(pos, mid + 1, tr, p << 1 | 1);
push_up(p);
}
node query(int l, int r, int tl, int tr, int p) {
if (l <= tl && tr <= r)
return t[p];
int mid = (tl + tr) >> 1;
if (mid < l)
return query(l, r, mid + 1, tr, p << 1 | 1);
if (mid >= r)
return query(l, r, tl, mid, p << 1);
return query(l, r, tl, mid, p << 1) +
query(l, r, mid + 1, tr, p << 1 | 1);
}
} T;

int main() {
//freopen("in", "r", stdin);
freopen("maze.in", "r", stdin);
freopen("maze.out", "w", stdout);
n = in(), m = in(), q = in();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
mp[i][j] = in();
T.build(1, m, 1);

int a, b, c, d;
node res;
while (q--) {
if (in() == 1) {
a = in(), b = in();
mp[a][b] ^= 1;
T.modify(b, 1, m, 1);
} else {
a = in(), b = in(), c = in(), d = in();
res = T.query(b, d, 1, m, 1);
printf("%d\n", res[a][c]);
}
}
return 0;
}


# T2、猛汉王

## $Sol$：

$cover(x)$ 表示 $x$ 能覆盖的白色点，$cover ( x, y )$ 表示 $x, y$ 共同覆盖到的白色点。

$\begin{eqnarray} Ans &=& \sum_{x, y \in S} \max \{cover(x) - cover{(x,y)}, cover(y) - cover(x, y) \} \notag \\ &=& \sum_{x, y \in S} \max \{ cover(x), cover(y) \} - \sum_{x, y \in S} cover(x, y) \notag \\ &=& \sum_{x, y \in S} \max \{ cover(x), cover(y) \} - \sum_{x \in S} \binom{cover(x)}{2} \notag \\ \end{eqnarray}$

## $Source$：

#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 = 1e5 + 5;
struct node {
int x, y;
} a[N], b[N];
struct options {
long long x; int y, z, id;
int typ;
} opt[N * 3];

int n, m, d, nn, cntx[N], cnty[N];
long long ans_min, ans_max;

long long tmp[N * 3];
inline bool cmpx(const options &i, const options &j) {
if (i.x == j.x)
return i.typ == 0 ? 1 : j.typ != 0;
return i.x < j.x;
}
void prep() {
nn = 0;
for (int i = 1; i <= m; ++i)
tmp[i] = b[i].y;
for (int i = 1; i <= n; ++i)
tmp[i + m] = 1ll * a[i].y - d;
for (int i = 1; i <= n; ++i)
tmp[i + n + m] = 1ll * a[i].y + d;
std::sort(tmp + 1, tmp + 1 + n + n + m);
nn = std::unique(tmp + 1, tmp + 1 + n + n + m) - tmp - 1;
for (int i = 1; i <= m; ++i) {
opt[i].typ = opt[i].id = 0;
opt[i].x = b[i].x;
opt[i].y = std::lower_bound(tmp + 1, tmp + 1 + nn, b[i].y) - tmp;
opt[i].z = 0;
}
for (int i = 1; i <= n; ++i) {
opt[i + m].typ = -1;
opt[i + m].id = i;
opt[i + m].x = 1ll * a[i].x - d - 1;

opt[i + n + m].typ = 1;
opt[i + n + m].id = i;
opt[i + n + m].x = 1ll * a[i].x + d;

opt[i + m].y = opt[i + n + m].y = std::lower_bound(tmp + 1, tmp + 1 + nn, 1ll * a[i].y - d) - tmp;
opt[i + m].z = opt[i + n + m].z = std::lower_bound(tmp + 1, tmp + 1 + nn, 1ll * a[i].y + d) - tmp;
}
std::sort(opt + 1, opt + 1 + n + n + m, cmpx);
}

struct binary_index_tree {
int a[N * 3];
inline void init() { memset(a, 0, sizeof(a)); }
void insert(int p, int k) { for (; p <= nn; p += (p & -p)) a[p] += k; }
int ask(int p, int ret = 0) { for (; p; p -= (p & -p)) ret += a[p]; return ret; }
} bit;

void work() {
prep();
bit.init();
for (int i = 1; i <= n + n + m; ++i) {
if (!opt[i].typ) {
bit.insert(opt[i].y, 1);
} else {
cntx[opt[i].id] += opt[i].typ * (bit.ask(opt[i].z) - bit.ask(opt[i].y - 1));
}
}
}

int main() {
//freopen("in", "r", stdin);
freopen("mhw.in", "r", stdin);
freopen("mhw.out", "w", stdout);
n = in(), m = in(), d = in();
for (int i = 1; i <= n; ++i) {
a[i] = (node){in(), in()};
a[i] = (node){a[i].x + a[i].y, a[i].x - a[i].y};
}
for (int i = 1; i <= m; ++i) {
b[i] = (node){in(), in()};
b[i] = (node){b[i].x + b[i].y, b[i].x - b[i].y};
}
work();
std::swap(a, b);
std::swap(n, m);
std::swap(cntx, cnty);
work();

std::sort(cntx + 1, cntx + 1 + n);
std::sort(cnty + 1, cnty + 1 + m);
for (int i = 1; i <= n; ++i) {
ans_min += 1ll * cntx[i] * (n - i);
ans_min -= 1ll * cntx[i] * (cntx[i] - 1) / 2;
ans_max += 1ll * cntx[i] * (i - 1);
ans_max -= 1ll * cntx[i] * (cntx[i] - 1) / 2;
}
for (int i = 1; i <= m; ++i) {
ans_min += 1ll * cnty[i] * (m - i);
ans_min -= 1ll * cnty[i] * (cnty[i] - 1) / 2;
ans_max += 1ll * cnty[i] * (i - 1);
ans_max -= 1ll * cnty[i] * (cnty[i] - 1) / 2;
}
printf("%lld %lld\n", ans_min, ans_max);
return 0;
}


# T3、工厂

## $Sol$：

$B$$A$ 是显然的，不再赘述；
$A$$B$ 可以用反证法：

$QED$

$f_{s,i}$ 表示当前选出联通块集合为 $s$，已经安排了点数和为 $2i$ 的联通块 (使它们满足上述条件) 的最小代价。

$\begin{eqnarray} f_{s \bigcup \{ x \},i} &=& \min(f_{s \bigcup \{ x \}, i}, f_{S,i}) \notag \\ f_{s, i} &=& \min_{j = 0} ^ {i - 1} \{ f_{s,j} + (i - j) ^ 2 \} \ , (\Sigma_{x \in s} = \Sigma_{y \in s}) \notag \end{eqnarray}$

## $Source$：

#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 = 35, inf = 0x3f3f3f3f;

int n, m, mp[N << 1][N << 1], tmp_x, tmp_y, init_edge, buc[N][N], pre[N << 1], f[172033][N], num[N << 1];
bool vis[N << 1];

struct node {
int x, y;
inline bool operator < (const node &b) const {
return buc[this->x][this->y] < buc[b.x][b.y];
}
inline bool operator == (const node &b) const {
return this->x == b.x && this->y == b.y;
}
} a[N + N];

void prep(const int u) {
vis[u] = 1;
if (u <= n)
++tmp_x;
else
++tmp_y;
for (int i = 1; i <= mp[u][0]; ++i)
if (!vis[mp[u][i]])
prep(mp[u][i]);
}

int main() {
//freopen("in", "r", stdin);
freopen("factory.in", "r", stdin);
freopen("factory.out", "w", stdout);
n = in();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
char c = getchar();
while (c < '0' || c > '1')
c = getchar();
if (c == '1') {
mp[i][++mp[i][0]] = j + n;
mp[j + n][++mp[j + n][0]] = i;
}
init_edge += c == '1';
}
for (int i = 1; i <= n + n; ++i)
if (!vis[i]) {
tmp_x = tmp_y = 0;
prep(i);
++buc[tmp_x][tmp_y];
}

for (int i = 0; i <= n; ++i)
for (int j = 0; j <= n; ++j)
if (buc[i][j])
a[++m] = (node){i, j};
std::sort(a + 1, a + 1 + m);
m = std::unique(a + 1, a + 1 + m) - a - 1;
pre[1] = 1;
for (int i = 2; i <= m + 1; ++i)
pre[i] = pre[i - 1] * (buc[a[i - 1].x][a[i - 1].y] + 1);

memset(f, inf, sizeof(f));
f[0][0] = 0;

int nowx, nowy;
for (int s = 0; s < (pre[m + 1]); ++s) {
nowx = nowy = 0;
for (int i = 1; i <= m; ++i)
num[i] = s % pre[i + 1] / pre[i];
for (int i = 1; i <= m; ++i)
nowx += num[i] * a[i].x, nowy += num[i] * a[i].y;
if (nowx == nowy)
for (int i = 0; i < nowx; ++i)
chk_min(f[s][nowx], f[s][i] + (nowx - i) * (nowx - i));
for (int i = 1; i <= m; ++i)
if (num[i] < buc[a[i].x][a[i].y])
for (int j = 0; j <= n; ++j)
chk_min(f[s + pre[i]][j], f[s][j]);
}
printf("%d\n", f[pre[m + 1] - 1][n] - init_edge);

return 0;
}



posted @ 2019-08-13 21:55  15owzLy1  阅读(64)  评论(1编辑  收藏