A. XORanges
化简一下可得,区间长度为奇数答案才可能不为 ,此时答案就是 这些位置数的异或和。奇偶分别维护一个树状数组即可。时间复杂度
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <random>
#include <bitset>
#include <queue>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <chrono>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = 100010;
int a[N * 2];
int fw[2][N];
int lowBit(int k) { return k & -k; }
int qr(int* fw, int k) {
int ret = 0;
while (k) {
ret ^= fw[k];
k &= k - 1;
}
return ret;
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
int n, q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i)
fw[i & 1][(i + 1) >> 1] = fw[i & 1][(i - 1) >> 1] ^ a[i];
n = (n + 1) >> 1;
for (int j = 0; j < 2; ++j)
for (int i = n; i; --i)
fw[j][i] ^= fw[j][i & (i - 1)];
while (q--) {
int opt, x, y;
scanf("%d%d%d", &opt, &x, &y);
if (opt == 1) {
int modi = a[x] ^ y;
int j = x & 1;
for (int k = (x + 1) >> 1; k <= n; k += lowBit(k))
fw[j][k] ^= modi;
a[x] = y;
} else if ((x ^ y) & 1)
puts("0");
else
printf("%d\n", qr(fw[x & 1], (x - 1) >> 1) ^ qr(fw[x & 1], (y + 1) >> 1));
}
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
B. Rack
减一之后就是 位的 bit-reverse。时间复杂度 或 。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <random>
#include <bitset>
#include <queue>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <chrono>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int P = 1000000007;
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
int n;
ll k;
scanf("%d%lld", &n, &k);
--k;
int ans = 0;
while (n--) {
ans = (ans << 1) | (k & 1);
k >>= 1;
if (ans >= P) ans -= P;
}
if (++ans == P) ans = 0;
printf("%d\n", ans);
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
C. Covering
如果一个位置周围有至少 个特殊格子,显然无解。如果一个位置周围有 个特殊格子,可以看成那两个特殊格子之间连边。如果有两个特殊格子贴边,那么它们的状态被唯一确定,可以唯一确定连通块的每个特殊格子摆法。如果连通块内有 条边,无解。如果连通块内有 条边,无论如何方案应该都是与这些特殊格子四相邻的恰好都被覆盖一次。如果连通块内有 条边,从恰相邻一个特殊格子的数中恰有一个可以不被选,减去那个最小的即可。时间复杂度 。
#include <cstdio>
#include <functional>
#include <vector>
#include <numeric>
#define GG do { puts("No"); return 0; } while (false)
using namespace std;
typedef long long ll;
int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};
int main() {
int n, m;
scanf("%d%d", &n, &m);
vector<vector<int>> a(n + 2, vector<int>(m + 2, -2e9));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &a[i][j]);
int k;
ll ans = 0;
scanf("%d", &k);
vector<vector<int>> label(n + 2, vector<int>(m + 2, 0));
vector<int> f(k + 1), mn(k + 1, 1e9), cn(k + 1, 1);
for (int i = 1; i <= k; ++i) {
int x, y;
scanf("%d%d", &x, &y);
++x; ++y;
ans += a[x][y];
label[x][y] = i;
for (int d = 0; d < 4; ++d)
ans += a[x + dx[d]][y + dy[d]];
}
iota(f.begin(), f.end(), 0);
function<int(int)> find = [&](int x) { return f[x] == x ? x : f[x] = find(f[x]); };
function<void(int, int)> merge = [&](int u, int v) {
if (u != v) {
f[v] = u;
mn[u] = min(mn[u], mn[v]);
cn[u] += cn[v];
}
};
for (int i = 1; i <= n; ++i) {
if (label[i][1])
mn[label[i][1]] = -2e9;
if (label[i][m])
mn[label[i][m]] = -2e9;
}
for (int i = 1; i <= m; ++i) {
if (label[1][i])
mn[label[1][i]] = -2e9;
if (label[n][i])
mn[label[n][i]] = -2e9;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
int cnt = 0;
for (int d = 0; d < 4; ++d)
if (label[i + dx[d]][j + dy[d]])
++cnt;
if (cnt >= 3 || label[i][j] && cnt >= 2) GG;
if (label[i][j] && cnt) {
for (int d = 0; d < 4; ++d)
if (label[i + dx[d]][j + dy[d]]) {
int u = find(label[i][j]), v = find(label[i + dx[d]][j + dy[d]]);
merge(u, v);
if (--cn[u] < 0) GG;
}
ans -= a[i][j];
} else if (cnt == 2) {
int u = 0, v = 0;
for (int d = 0; d < 4; ++d)
if (label[i + dx[d]][j + dy[d]]) {
int cur = find(label[i + dx[d]][j + dy[d]]);
if (!u) u = cur;
else v = cur;
}
merge(u, v);
if (--cn[u] < 0) GG;
ans -= a[i][j];
mn[u] = min(mn[u], a[i][j]);
} else if (cnt == 1)
for (int d = 0; d < 4; ++d)
if (label[i + dx[d]][j + dy[d]]) {
int u = find(label[i + dx[d]][j + dy[d]]);
mn[u] = min(mn[u], a[i][j]);
}
}
for (int i = 1; i <= k; ++i)
if (f[i] == i && cn[i])
ans -= mn[i];
if (ans < 0) GG;
printf("%lld\n", ans);
return 0;
}
D. Tower
不难猜到解能达到下界
(当
时为特例)
考虑构造,如果选择区间均为
,那么数值就是不断
,考虑二进制位差分即可。
#include <cstdio>
#include <functional>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
typedef long long ll;
int main() {
int t;
scanf("%d", &t);
while (t--) {
ll q;
scanf("%lld", &q);
if (q == 1) {
puts("0");
continue;
}
if (!(q & (q - 1))) {
int s = 0;
while ((1LL << s) != q) ++s;
printf("%d\n", s + 1);
for (int i = 1; i <= s + 1; ++i)
printf("%d %d\n", 1, i);
continue;
}
int s = 0;
while ((1LL << s) < q) ++s;
printf("%d\n", s + 1);
puts("1 1");
int cnt = 1;
int res = 1;
for (int i = s - 1; i >= 0; --i) {
if ((q >> i) & 1) {
if (((q << 1) >> i) & 1)
;
else
res = 3 - res;
} else {
if (((q << 1) >> i) & 1)
res = 3 - res;
}
printf("%d %d\n", res, ++cnt);
}
}
return 0;
}
E. Colouring a rectangle
黑白染色后两部分独立,线段树优化 DP。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <random>
#include <bitset>
#include <queue>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <chrono>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
struct Node {
ll v, lazy;
int l, r;
Node *ls, *rs;
ll get() const { return v + lazy; }
void upd() {
v = max(ls->get(), rs->get());
}
void pd() {
if (lazy) {
v += lazy;
ls->lazy += lazy;
rs->lazy += lazy;
lazy = 0;
}
}
void ch(int l, int r, ll v) {
if (this->l == l && this->r == r) {
lazy += v;
return;
}
pd();
if (r <= ls->r)
ls->ch(l, r, v);
else if (l >= rs->l)
rs->ch(l, r, v);
else {
ls->ch(l, ls->r, v);
rs->ch(rs->l, r, v);
}
upd();
}
};
const int N = 200010;
int n, m;
int a[N * 2], b[N * 2];
Node* build(int l, int r) {
static Node pool[N * 4], *top = pool;
Node* p = top++;
p->l = l;
p->r = r;
if (l == r)
return p;
int mid = (l + r) >> 1;
p->ls = build(l, mid);
p->rs = build(mid + 1, r);
return p;
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
scanf("%d%d", &n, &m);
for (int i = 1; i <= n + m - 1; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n + m - 1; ++i) scanf("%d", &b[i]);
if (n < m) {
swap(n, m);
} else
reverse(a + 1, a + n + m);
Node *seg1 = build(0, n + 1), *seg2 = build(0, n + 1);
for (int i = 1; i <= n + m - 1; ++i) {
if (i & 1) seg1->ch(i / 2 + 1, i / 2 + 1, seg1->get() + b[i]);
else seg2->ch(i / 2, i / 2, seg2->get() + b[i]);
if (i >= n) {
int len = i - n + 1;
if (i & 1)
seg1->ch(0, max(0, i / 2 + 1 - len), a[i - n + 1]);
else
seg2->ch(0, max(0, i / 2 - len), a[i - n + 1]);
}
if (i == n + m - 1) break;
if (i >= m) {
int len = m;
if (i <= m * 2 - 1)
len = i - m + 1;
if (i & 1)
seg1->ch(0, i / 2 + 1 - len, a[n + m * 2 - i - 1]);
else
seg2->ch(0, i / 2 - len, a[n + m * 2 - i - 1]);
}
}
printf("%lld\n", accumulate(a + 1, a + n + m, 0LL) + accumulate(b + 1, b + n + m, 0LL) - seg1->get() - seg2->get());
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
F. Adventure
最短路。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <numeric>
#include <functional>
#include <queue>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
const int N = 510;
int n, m;
char s[N][N];
int dis[N][N];
queue<pair<int, int>> pq[4];
int dx[] = {-1, 0, 1, 0},
dy[] = {0, 1, 0, -1};
int dir[256];
int main() {
// freopen("test.in", "r", stdin);
// freopen("test.out", "w", stdout);
dir['N'] = 0;
dir['E'] = 1;
dir['S'] = 2;
dir['W'] = 3;
scanf("%d%d", &n, &m);
if (n == 1 && m == 1) {
puts("0");
return 0;
}
for (int i = 1; i <= n; ++i)
scanf("%s", s[i] + 1);
memset(dis, -1, sizeof(dis));
pq[0].emplace(1, 1);
dis[1][1] = 0;
int r = -1;
for (int i = 0; i % 4 != r; ++i) {
if (pq[i % 4].empty()) continue;
else {
r = i % 4;
while (!pq[r].empty()) {
int x, y;
tie(x, y) = pq[r].front();
if (x == n && y == m) {
printf("%d\n", dis[x][y]);
return 0;
}
pq[r].pop();
if (dis[x][y] % 4 != r || s[x][y] == 'X') continue;
for (int i = 0; i < 4; ++i) {
int gx = x + dx[(dir[s[x][y]] + i) % 4],
gy = y + dy[(dir[s[x][y]] + i) % 4];
if (gx < 1 || gx > n || gy < 1 || gy > m) continue;
if (dis[gx][gy] == -1 || dis[gx][gy] > dis[x][y] + i) {
dis[gx][gy] = dis[x][y] + i;
pq[dis[gx][gy] % 4].emplace(gx, gy);
}
}
}
}
}
puts("-1");
return 0;
}