Last chance
线段树优化连边,输出方案先输出容量为 2 2 2 的。
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
namespace flow {
struct edge_t {
int to, cap, rev;
edge_t(int t, int c, int r) {
to = t;
cap = c;
rev = r;
}
};
int n, source, sink, answer;
vector<vector<edge_t>> adj;
vector<int> dist, current;
void init(int v, int s, int t) {
n = v;
source = s;
sink = t;
answer = 0;
adj.clear();
adj.resize(n);
dist.resize(n);
current.resize(n);
}
void add(int x, int y, int c) {
adj[x].emplace_back(y, c, adj[y].size());
adj[y].emplace_back(x, 0, adj[x].size() - 1);
}
bool bfs() {
queue<int> q;
for (int i = 0; i < n; ++i) {
dist[i] = -1;
}
dist[source] = 0, q.push(source);
while (!q.empty()) {
int x = q.front();
q.pop();
for (auto e : adj[x]) {
if (e.cap && !~dist[e.to]) {
dist[e.to] = dist[x] + 1;
if (e.to == sink) {
return true;
}
q.push(e.to);
}
}
}
return false;
}
int dfs(int x, int f) {
if (x == sink) {
return f;
}
for (int &i = current[x]; ~i; --i) {
edge_t &e = adj[x][i];
if (e.cap && dist[e.to] == dist[x] + 1) {
int w = dfs(e.to, min(e.cap, f));
if (w) {
e.cap -= w;
adj[e.to][e.rev].cap += w;
return w;
}
}
}
return 0;
}
int max_flow() {
while (bfs()) {
for (int i = 0; i < n; ++i) {
current[i] = adj[i].size() - 1;
}
while (true) {
int flow = dfs(source, inf);
if (!flow) {
break;
}
answer += flow;
}
}
return answer;
}
}
using flow::source;
using flow::sink;
using flow::init;
using flow::add;
using flow::max_flow;
using flow::adj;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
init((m << 1) - 1 + n + 2, (m << 1) - 1 + n, (m << 1) - 1 + n + 1);
vector<int> id(m);
vector<int> related((m << 1) - 1);
function<void(int, int, int)> build = [&](int x, int l, int r) {
if (l == r) {
id[l] = x;
related[x] = l;
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
build(x + 1, l, y);
build(z, y + 1, r);
add(x, x + 1, inf);
add(x, z, inf);
}
};
function<void(int, int, int, int, int, int)> query = [&](int x, int l, int r, int ql, int qr, int from) {
if (l == ql && r == qr) {
add(from, x, 1);
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
if (qr <= y) {
query(x + 1, l, y, ql, qr, from);
} else if (ql > y) {
query(z, y + 1, r, ql, qr, from);
} else {
query(x + 1, l, y, ql, y, from);
query(z, y + 1, r, y + 1, qr, from);
}
}
};
build(0, 0, m - 1);
for (int i = 0; i < m; ++i) {
add(id[i], sink, 1);
}
vector<int> type(n), a(n), b(n), c(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &type[i]);
if (!type[i]) {
add(source, i + (m << 1) - 1, 1);
int size;
scanf("%d", &size);
while (size--) {
int x;
scanf("%d", &x);
--x;
add(i + (m << 1) - 1, id[x], 1);
}
} else if (type[i] == 1) {
scanf("%d %d", &a[i], &b[i]);
--a[i];
--b[i];
add(source, i + (m << 1) - 1, 1);
query(0, 0, m - 1, a[i], b[i], i + (m << 1) - 1);
} else {
scanf("%d %d %d", &a[i], &b[i], &c[i]);
--a[i];
--b[i];
--c[i];
add(source, i + (m << 1) - 1, 2);
add(i + (m << 1) - 1, id[a[i]], 1);
add(i + (m << 1) - 1, id[b[i]], 1);
add(i + (m << 1) - 1, id[c[i]], 1);
}
}
printf("%d\n", max_flow());
vector<bool> use(m);
for (int i = 0; i < m; ++i) {
for (auto e : adj[id[i]]) {
if (e.to == sink && !e.cap) {
use[i] = true;
}
}
}
for (int i = 0; i < n; ++i) {
if (type[i] == 2) {
bool found = false;
for (auto e : adj[i + (m << 1) - 1]) {
if (e.to == source && e.cap) {
found = true;
break;
}
}
if (found) {
int remain = 2;
for (auto e : adj[i + (m << 1) - 1]) {
if (e.to != source && !e.cap) {
printf("%d %d\n", i + 1, related[e.to] + 1);
--remain;
use[related[e.to]] = false;
}
}
if (remain && use[a[i]]) {
printf("%d %d\n", i + 1, a[i] + 1);
--remain;
use[a[i]] = false;
}
if (remain && use[b[i]]) {
printf("%d %d\n", i + 1, b[i] + 1);
--remain;
use[b[i]] = false;
}
if (remain && use[c[i]]) {
printf("%d %d\n", i + 1, c[i] + 1);
--remain;
use[c[i]] = false;
}
}
}
}
for (int i = 0; i < n; ++i) {
if (!type[i]) {
for (auto e : adj[i + (m << 1) - 1]) {
if (e.to != source && !e.cap && use[related[e.to]]) {
printf("%d %d\n", i + 1, related[e.to] + 1);
use[related[e.to]] = false;
}
}
}
}
for (int i = 0; i < m; ++i) {
if (use[i]) {
int p = -1;
for (int j = 0; j < n; ++j) {
if (type[j] == 1 && a[j] <= i && b[j] >= i && (!~p || b[j] < b[p])) {
p = j;
}
}
type[p] = -1;
printf("%d %d\n", p + 1, i + 1);
}
}
return 0;
}
Space Isaac
如果一个数不能被表示那么它减去 a i a_i ai 仍然在 a a a 中。
假设这个数是 a 0 + a i a_0 + a_i a0+ai ,不难发现需要满足 a 0 + a i = a 1 + a i − 1 = a 2 + a i − 2 ⋯ a_0 + a_i = a_1 + a_{i-1} = a_2 + a_{i-2}\cdots a0+ai=a1+ai−1=a2+ai−2⋯ 。差分之后相当于判两部分是不是回文。
#include <bits/stdc++.h>
using namespace std;
vector<int> manacher(vector<int> a) {
int n = a.size(), m = (n << 1) - 1;
vector<int> b(m, -1), p(m, 0);
for (int i = 0; i < n; ++i) {
b[i << 1] = a[i];
}
int x = 0;
for (int i = 1; i < m; ++i) {
if (i <= x + p[x]) {
p[i] = min(p[(x << 1) - i], x + p[x] - i);
}
while (i - p[i] - 1 >= 0 && i + p[i] + 1 < m && b[i - p[i] - 1] == b[i + p[i] + 1]) {
++p[i];
}
if (i + p[i] >= x + p[x]) {
x = i;
}
}
for (int i = 0; i < m; ++i) {
if (i - p[i] == 0 || i + p[i] == m - 1) {
++p[i];
}
}
for (int i = 0; i < m; ++i) {
p[i] >>= 1;
}
return p;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
vector<int> a(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
vector<int> b(n);
for (int i = 0; i < n - 1; ++i) {
b[i] = a[i + 1] - a[i];
}
b[n - 1] = (a[0] + m - a[n - 1]) % m;
vector<int> p = manacher(b);
vector<int> answer;
auto palindrome = [&](int l, int r) {
return l == r || p[l + r - 1] >= r - l >> 1;
};
for (int i = 0; i < n; ++i) {
if (palindrome(0, i) && palindrome(i, n)) {
answer.push_back((a[0] + a[i]) % m);
}
}
printf("%d\n", answer.size());
if (!answer.empty()) {
vector<int> temp;
int p = min_element(answer.begin(), answer.end()) - answer.begin();
for (int j = p; j < answer.size(); ++j) {
temp.push_back(answer[j]);
}
for (int j = 0; j < p; ++j) {
temp.push_back(answer[j]);
}
for (int j = 0; j < temp.size(); ++j) {
printf("%d%c", temp[j], j == temp.size() - 1 ? '\n' : ' ');
}
}
return 0;
}
Hyperspace Highways
建个圆方树。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m, q;
scanf("%d %d %d", &n, &m, &q);
vector<vector<int>> adj(n), graph(n);
for (int i = 0; i < m; ++i) {
int x, y;
scanf("%d %d", &x, &y);
--x;
--y;
graph[x].push_back(y);
graph[y].push_back(x);
}
vector<int> dfn(n, -1), low(n, -1), stack;
int dfn_t = 0;
m = n;
function<void(int, int)> tarjan = [&](int x, int parent) {
dfn[x] = low[x] = dfn_t++;
stack.push_back(x);
for (auto y : graph[x]) {
if (y != parent) {
if (!~dfn[y]) {
tarjan(y, x);
low[x] = min(low[x], low[y]);
if (dfn[x] <= low[y]) {
adj.push_back(vector<int>());
adj[x].push_back(m);
int z;
do {
z = stack.back();
stack.pop_back();
adj[m].push_back(z);
} while (z != y);
++m;
}
} else {
low[x] = min(low[x], dfn[y]);
}
}
}
};
tarjan(0, -1);
int log_m = 0;
while (1 << log_m < m) {
++log_m;
}
vector<vector<int>> ancestor(log_m, vector<int> (m, -1));
vector<int> depth(m), dist(m);
function<void(int)> dfs = [&](int x) {
for (int i = 1; depth[x] >> i; ++i) {
ancestor[i][x] = ancestor[i - 1][ancestor[i - 1][x]];
}
for (auto y : adj[x]) {
ancestor[0][y] = x;
depth[y] = depth[x] + 1;
dist[y] = dist[x] + 1 - (y >= n);
dfs(y);
}
};
auto lca = [&](int x, int y) {
if (depth[x] < depth[y]) {
swap(x, y);
}
for (int i = 0; depth[x] > depth[y]; ++i) {
if (depth[x] - depth[y] >> i & 1) {
x = ancestor[i][x];
}
}
if (x == y) {
return x;
}
for (int i = log_m - 1; ~i; --i) {
if (ancestor[i][x] != ancestor[i][y]) {
x = ancestor[i][x];
y = ancestor[i][y];
}
}
return ancestor[0][x];
};
dfs(0);
while (q--) {
int x, y;
scanf("%d %d", &x, &y);
--x;
--y;
int z = lca(x, y);
printf("%d\n", dist[x] + dist[y] - (dist[z] << 1) - (z >= n));
}
return 0;
}
Interstellar battle
期望等于每个点存在的概率减去每条边两个点都存在的概率。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<double> prob(n), sum(n);
for (int i = 0; i < n; ++i) {
scanf("%lf", &prob[i]);
prob[i] = 1 - prob[i];
}
vector<vector<int>> adj(n);
for (int i = 0; i < n - 1; ++i) {
int x, y;
scanf("%d %d", &x, &y);
adj[x].push_back(y);
adj[y].push_back(x);
}
vector<int> parent(n, -1);
function<void(int)> dfs = [&](int x) {
for (auto y : adj[x]) {
if (y != parent[x]) {
sum[x] += prob[y];
parent[y] = x;
dfs(y);
}
}
};
dfs(0);
double answer = 0;
for (int i = 0; i < n; ++i) {
answer += prob[i] * (1 - sum[i]);
}
int m;
scanf("%d", &m);
while (m--) {
int x;
double delta;
scanf("%d %lf", &x, &delta);
delta = 1 - delta - prob[x];
answer += delta * (1 - sum[x]);
prob[x] += delta;
if (x) {
answer -= prob[parent[x]] * delta;
sum[parent[x]] += delta;
}
printf("%lf\n", answer);
}
return 0;
}
Ancient civilizations
如果凸包上颜色超过 2 2 2 段则无解,否则可以用一个类似三角剖分的过程来解决:
定义 s o l v e ( a , b , c ) solve(a, b, c) solve(a,b,c) 表示 a a a 是一种颜色, b , c b, c b,c 是一种颜色并且有边 ( b , c ) (b, c) (b,c) ,然后要连上三角形内部的所有边,找到一个与 a a a 同色的点 d d d ,连接 ( a , d ) (a, d) (a,d) ,递归计算,如果不存在直接所有内部点都往 c c c 连就行了。
#include <bits/stdc++.h>
using namespace std;
struct point_t {
int x, y, id, color;
point_t() {
}
point_t(int x, int y):x(x), y(y) {
}
bool operator < (const point_t &b) const {
return x < b.x || (x == b.x && y < b.y);
}
point_t operator - (const point_t &b) const {
return point_t(x - b.x, y - b.y);
}
long long operator * (const point_t &b) const {
return (long long)x * b.y - (long long)y * b.x;
}
};
vector<point_t> convex_hull(vector<point_t> points) {
sort(points.begin(), points.end());
vector<point_t> hull;
for (int iter = 0; iter < 2; ++iter) {
int limit = hull.size();
for (auto p : points) {
while (hull.size() > limit + 1 && (hull[hull.size() - 1] - hull[hull.size() - 2]) * (p - hull[hull.size() - 2]) <= 0) {
hull.pop_back();
}
hull.push_back(p);
}
hull.pop_back();
reverse(points.begin(), points.end());
}
return hull;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<pair<int, int>> answer;
vector<point_t> p(n);
bool same = true;
for (int i = 0; i < n; ++i) {
scanf("%d %d %d", &p[i].x, &p[i].y, &p[i].color);
p[i].id = i;
if (p[i].color != p[0].color) {
same = false;
}
}
if (same) {
printf("%d\n", n - 1);
for (int i = 1; i < n; ++i) {
printf("%d %d\n", 0, i);
}
return 0;
}
vector<point_t> hull = convex_hull(p);
int diff = 0;
for (int i = 0; i < hull.size(); ++i) {
if (hull[i].color != hull[(i + 1) % hull.size()].color) {
++diff;
}
}
if (diff > 2) {
puts("Impossible");
return 0;
}
auto in_triangle = [&](point_t p, point_t a, point_t b, point_t c) {
if (p.id == a.id || p.id == b.id || p.id == c.id) {
return false;
}
int ab = (a - p) * (b - p) > 0, bc = (b - p) * (c - p) > 0, ca = (c - p) * (a - p) > 0;
return ab == bc && bc == ca;
};
function<void(vector<point_t>, point_t, point_t, point_t)> solve = [&](vector<point_t> all, point_t a, point_t b, point_t c) {
if (all.empty()) {
return;
}
int p = -1;
for (int i = 0; i < all.size(); ++i) {
if (all[i].color == a.color) {
p = i;
break;
}
}
if (~p) {
point_t d = all[p];
answer.emplace_back(a.id, d.id);
vector<point_t> ab, bc, ca;
for (auto p : all) {
if (in_triangle(p, a, b, d)) {
ab.push_back(p);
}
if (in_triangle(p, b, c, d)) {
bc.push_back(p);
}
if (in_triangle(p, c, a, d)) {
ca.push_back(p);
}
}
solve(ab, b, a, d);
solve(bc, d, b, c);
solve(ca, c, a, d);
} else {
for (auto p : all) {
answer.emplace_back(p.id, c.id);
}
}
};
if (!diff) {
for (int i = 1; i < hull.size(); ++i) {
answer.emplace_back(hull[i - 1].id, hull[i].id);
}
int middle = -1;
for (int i = 0; i < n; ++i) {
if (p[i].color != hull[0].color) {
middle = i;
break;
}
}
for (int i = 0; i < hull.size(); ++i) {
vector<point_t> all;
for (int j = 0; j < n; ++j) {
if (in_triangle(p[j], hull[i], hull[(i + 1) % hull.size()], p[middle])) {
all.push_back(p[j]);
}
}
solve(all, p[middle], hull[i], hull[(i + 1) % hull.size()]);
}
} else {
int first = 0;
while (first < hull.size() && hull[first].color == hull[0].color) {
++first;
}
rotate(hull.begin(), hull.begin() + first, hull.end());
first = 0;
while (first < hull.size() && hull[first].color == hull[0].color) {
++first;
}
for (int i = 1; i < first; ++i) {
answer.emplace_back(hull[i - 1].id, hull[i].id);
vector<point_t> all;
for (int j = 0; j < n; ++j) {
if (in_triangle(p[j], hull[first], hull[i], hull[i - 1])) {
all.push_back(p[j]);
}
}
solve(all, hull[first], hull[i], hull[i - 1]);
}
for (int i = first + 1; i < hull.size(); ++i) {
answer.emplace_back(hull[i - 1].id, hull[i].id);
vector<point_t> all;
for (int j = 0; j < n; ++j) {
if (in_triangle(p[j], hull[0], hull[i], hull[i - 1])) {
all.push_back(p[j]);
}
}
solve(all, hull[0], hull[i], hull[i - 1]);
}
}
printf("%d\n", answer.size());
for (auto p : answer) {
printf("%d %d\n", p.first, p.second);
}
return 0;
}
Shady Lady
一个结论是:将 x a y b x^ay^b xayb 当成平面上的点 ( a , b ) (a, b) (a,b) ,一个式子有界当且仅当这个式子的所有点加上原点构成的凸包上的点坐标都是偶数。
对于一个这样的凸包 P P P ,可以给出构造:凸包上的点系数取 n n n ,其他点系数取 1 1 1 ,则凸包内部的点 Q = ( a , b ) Q = (a, b) Q=(a,b) 假设可以表示成 ∑ α i P i ( ∑ α i = 1 ) \sum \alpha_i P_i(\sum \alpha_i = 1) ∑αiPi(∑αi=1) ,则根据均值不等式可以推出 ∑ α i x x i y y i ≥ ∣ x a y b ∣ \sum \alpha_i x^{x_i} y^{y_i}\ge |x^ay^b| ∑αixxiyyi≥∣xayb∣ 。
否则,考虑一个横坐标(纵坐标同理)为奇数的点 Q = ( a , b ) Q = (a, b) Q=(a,b) ,一定有一条直线可以截这个点,假设原点到这条直线的向量是 ( p , q ) (p, q) (p,q) ,用 ( − ∞ p , ∞ q ) (-\infty^p, \infty^q) (−∞p,∞q) 就可以让它没有下界。
如果原凸包上有解则一定有解,否则一定是去掉 P i P_i Pi 之后在 P i − 1 , P i + 1 P_{i-1}, P_{i+1} Pi−1,Pi+1 之间的新点构成凸包存在奇数坐标的点,注意到这些过程可以一起做:将凸包黑白染色,删去黑点和白点分别再做一次凸包检验即可。
#include <bits/stdc++.h>
using namespace std;
struct point_t {
int x, y, id;
point_t() {
}
point_t(int x, int y):x(x), y(y) {
}
point_t(int x, int y, int id):x(x), y(y), id(id) {
}
bool operator < (const point_t &b) const {
return x < b.x || (x == b.x && y < b.y);
}
point_t operator - (const point_t &b) const {
return point_t(x - b.x, y - b.y);
}
long long operator * (const point_t &b) const {
return (long long)x * b.y - (long long)y * b.x;
}
};
vector<point_t> convex_hull(vector<point_t> points) {
sort(points.begin(), points.end());
vector<point_t> hull;
for (int iter = 0; iter < 2; ++iter) {
int limit = hull.size();
for (auto p : points) {
while (hull.size() > limit + 1 && (hull[hull.size() - 1] - hull[hull.size() - 2]) * (p - hull[hull.size() - 2]) <= 0) {
hull.pop_back();
}
hull.push_back(p);
}
hull.pop_back();
reverse(points.begin(), points.end());
}
return hull;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<point_t> p(n);
bool origin = false;
for (int i = 0; i < n; ++i) {
scanf("%d %d", &p[i].x, &p[i].y);
if (!p[i].x && !p[i].y) {
origin = true;
}
p[i].id = i;
}
if (!origin) {
p.emplace_back(0, 0, n++);
}
vector<point_t> hull = convex_hull(p);
for (auto p : hull) {
if ((p.x & 1) || (p.y & 1)) {
puts("Ani");
return 0;
}
}
{
vector<bool> ban(n);
for (int i = 1; i < hull.size(); i += 2) {
ban[hull[i].id] = true;
}
vector<point_t> q;
for (int i = 0; i < n; ++i) {
if (!ban[i]) {
q.push_back(p[i]);
}
}
q = convex_hull(q);
for (auto p : q) {
if ((p.x & 1) || (p.y & 1)) {
puts("Ani");
return 0;
}
}
}
{
vector<bool> ban(n);
for (int i = 2; i < hull.size(); i += 2) {
ban[hull[i].id] = true;
}
vector<point_t> q;
for (int i = 0; i < n; ++i) {
if (!ban[i]) {
q.push_back(p[i]);
}
}
q = convex_hull(q);
for (auto p : q) {
if ((p.x & 1) || (p.y & 1)) {
puts("Ani");
return 0;
}
}
}
puts("Borna");
return 0;
}
AI robots
按照 r r r 从大到小排序,那么只需要考虑当前的限制,暴力枚举 q q q 那一维,坐标那一维用个数据结构维护。
#include <bits/stdc++.h>
using namespace std;
struct fenwick_t {
vector<int> all, fenw;
int n;
void init() {
sort(all.begin(), all.end());
all.erase(unique(all.begin(), all.end()), all.end());
n = all.size();
fenw.resize(n);
}
void modify(int x) {
x = lower_bound(all.begin(), all.end(), x) - all.begin();
while (x < n) {
++fenw[x];
x |= x + 1;
}
}
int query(int x) {
int result = 0;
while (x >= 0) {
result += fenw[x];
x = (x & x + 1) - 1;
}
return result;
}
int query(int l, int r) {
return query(upper_bound(all.begin(), all.end(), r) - all.begin() - 1) - query(lower_bound(all.begin(), all.end(), l) - all.begin() - 1);
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
vector<int> x(n), r(n), q(n), p(n), disc(n);
for (int i = 0; i < n; ++i) {
scanf("%d %d %d", &x[i], &r[i], &q[i]);
disc[i] = q[i];
p[i] = i;
}
sort(disc.begin(), disc.end());
disc.erase(unique(disc.begin(), disc.end()), disc.end());
vector<fenwick_t> fenwick(disc.size());
auto id = [&](int x) {
int p = lower_bound(disc.begin(), disc.end(), x) - disc.begin();
if (p < disc.size() && disc[p] == x) {
return p;
} else {
return -1;
}
};
for (int i = 0; i < n; ++i) {
fenwick[id(q[i])].all.push_back(x[i]);
}
for (int i = 0; i < disc.size(); ++i) {
fenwick[i].init();
}
sort(p.begin(), p.end(), [&](const int &x, const int &y) {
return r[x] > r[y];
});
long long answer = 0;
for (auto i : p) {
for (int j = q[i] - m; j <= q[i] + m; ++j) {
int p = id(j);
if (~p) {
answer += fenwick[p].query(x[i] - r[i], x[i] + r[i]);
}
}
fenwick[id(q[i])].modify(x[i]);
}
printf("%lld\n", answer);
return 0;
}
Self-exploration
将最后的数中 00 00 00 和 11 11 11 缩起来,不难发现 0 ≤ c 10 − c 01 ≤ 1 0\le c_{10} - c_{01}\le 1 0≤c10−c01≤1 。所以可以快速算出有多少个 0 0 0 和多少个 1 1 1 已经 0 0 0 和 1 1 1 有多少段。如果没有上界限制答案就是两个组合数乘起来,有上界枚举哪一维脱离上界计算即可。
#include <bits/stdc++.h>
using namespace std;
const int md = 1e9 + 7;
int add(int x, int y) {
x += y;
if (x >= md) {
x -= md;
}
return x;
}
int sub(int x, int y) {
x -= y;
if (x < 0) {
x += md;
}
return x;
}
int mul(int x, int y) {
return (long long)x * y % md;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
string low, high;
cin >> low >> high;
for (int i = high.length() - 1; ~i; --i) {
if (high[i] == '0') {
high[i] = '1';
break;
} else {
high[i] = '0';
if (!i) {
high = "1" + high;
}
}
}
int zz, zo, oz, oo;
cin >> zz >> zo >> oz >> oo;
if (oz - zo < 0 || oz - zo > 1) {
puts("0");
return 0;
}
int one = oz + (oz == zo), zero = zo + (oz > zo), ones = one + oo, zeros = zero + zz, n = ones + zeros;
vector<int> fac(n + 1), ifac(n + 1);
fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
for (int i = 2; i <= n; ++i) {
fac[i] = mul(fac[i - 1], i);
ifac[i] = mul(md - md / i, ifac[md % i]);
}
for (int i = 2; i <= n; ++i) {
ifac[i] = mul(ifac[i], ifac[i - 1]);
}
auto binom = [&](int x, int y) {
if (x < 0 || y < 0 || x < y) {
return 0;
} else {
return mul(fac[x], mul(ifac[y], ifac[x - y]));
}
};
auto solve = [&](string limit) {
if (limit.length() < n) {
return 0;
} else if (limit.length() > n) {
return mul(binom(ones - 1, one - 1), !zeros && !zero ? 1 : binom(zeros - 1, zero - 1));
} else {
int o = 0, z = 0, os = 0, zs = 0, last = 0, answer = 0;
for (int i = 0; i < limit.size(); ++i) {
if (i && limit[i] == '1') {
++zs;
if (last) {
++z;
}
answer = add(answer, mul(ones == os && one == o ? 1 : binom(ones - os - 1, one - o - 1), binom(zeros - zs, zero - z)));
--zs;
if (last) {
--z;
}
}
if (limit[i] == '1') {
++os;
if (!last) {
last = 1;
++o;
}
} else {
++zs;
if (last) {
last = 0;
++z;
}
}
}
return answer;
}
};
printf("%d\n", sub(solve(high), solve(low)));
return 0;
}
Palindrome Pairs
暴力。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
cin >> n;
map<int, int> a;
for (int i = 0; i < n; ++i) {
string s;
cin >> s;
int state = 0;
for (auto c : s) {
state ^= 1 << c - 'a';
}
++a[state];
}
long long answer = 0;
for (auto p : a) {
if (p.second) {
answer += (long long)p.second * (p.second - 1);
for (int i = 0; i < 26; ++i) {
answer += (long long)p.second * a[p.first ^ 1 << i];
}
}
}
printf("%lld\n", answer >> 1);
return 0;
}
Moonwalk challenge
暴力提取 LCA 附近的一段,其他部分一定是返祖链,维护哈希即可。
#include <bits/stdc++.h>
using namespace std;
const int base = 2333;
const int md0 = 1e9 + 7;
const int md1 = 1e9 + 9;
struct hash_t {
int hash0, hash1;
hash_t(int hash0 = 0, int hash1 = 0):hash0(hash0), hash1(hash1) {
}
hash_t operator + (const int &x) const {
return hash_t((hash0 + x) % md0, (hash1 + x) % md1);
};
hash_t operator * (const int &x) const {
return hash_t((long long)hash0 * x % md0, (long long)hash1 * x % md1);
}
hash_t operator - (const hash_t &x) const {
return hash_t((hash0 + md0 - x.hash0) % md0, (hash1 + md1 - x.hash1) % md1);
};
hash_t operator * (const hash_t &x) const {
return hash_t((long long)hash0 * x.hash0 % md0, (long long)hash1 * x.hash1 % md1);
}
long long get() {
return (long long)hash0 * md1 + hash1;
}
};
vector<int> kmp(vector<int> a) {
int n = a.size();
vector<int> fail(n);
fail[0] = -1;
for (int i = 1; i < n; ++i) {
fail[i] = fail[i - 1];
while (~fail[i] && a[fail[i] + 1] != a[i]) {
fail[i] = fail[fail[i]];
}
if (a[fail[i] + 1] == a[i]) {
++fail[i];
}
}
return fail;
}
int match(vector<int> a, vector<int> b) {
vector<int> fail = kmp(b);
int n = a.size(), m = b.size(), result = 0;
for (int i = 0, j = -1; i < n; ++i) {
while (~j && a[i] != b[j + 1]) {
j = fail[j];
}
if (a[i] == b[j + 1]) {
++j;
}
if (j == m - 1) {
++result;
j = fail[j];
}
}
return result;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
const int m = 100;
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<vector<pair<int, int>>> adj(n);
for (int i = 0; i < n - 1; ++i) {
int x, y;
string s;
cin >> x >> y >> s;
--x;
--y;
adj[x].emplace_back(y, s[0] - 'a' + 1);
adj[y].emplace_back(x, s[0] - 'a' + 1);
}
int log_n = 0;
while (1 << log_n < n) {
++log_n;
}
vector<vector<int>> jump(m + 1, vector<int> (n, -1)), parent(log_n, vector<int> (n, -1));
vector<hash_t> hash(n), power(n);
vector<int> depth(n), value(n);
power[0] = hash_t(1, 1);
for (int i = 1; i < n; ++i) {
power[i] = power[i - 1] * base;
}
function<void(int)> dfs = [&](int x) {
for (int i = 1; depth[x] >> i; ++i) {
parent[i][x] = parent[i - 1][parent[i - 1][x]];
}
jump[0][x] = x;
for (int i = 1; i <= m && i <= depth[x]; ++i) {
jump[i][x] = jump[i - 1][parent[0][x]];
}
for (auto e : adj[x]) {
int y = e.first, w = e.second;
if (y != parent[0][x]) {
value[y] = w;
parent[0][y] = x;
depth[y] = depth[x] + 1;
hash[y] = hash[x] * base + w;
dfs(y);
}
}
};
auto go_up = [&](int x, int d) {
for (int i = 0; depth[x] > d; ++i) {
if (depth[x] - d >> i & 1) {
x = parent[i][x];
}
}
return x;
};
auto lca = [&](int x, int y) {
if (depth[x] < depth[y]) {
swap(x, y);
}
x = go_up(x, depth[y]);
if (x == y) {
return x;
}
for (int i = log_n - 1; ~i; --i) {
if (parent[i][x] != parent[i][y]) {
x = parent[i][x];
y = parent[i][y];
}
}
return parent[0][x];
};
dfs(0);
int q;
cin >> q;
vector<int> answer(q);
vector<vector<pair<int, pair<long long, int>>>> event(m + 1);
for (int i = 0; i < q; ++i) {
int x, y;
string s;
cin >> x >> y >> s;
--x;
--y;
if (x == y) {
continue;
}
int l = s.length(), z = lca(x, y);
int u = go_up(x, min(depth[x], depth[z] + l - 1));
int v = go_up(y, min(depth[y], depth[z] + l - 1));
vector<int> left, right;
for (int t = u; t != z; t = parent[0][t]) {
left.push_back(value[t]);
}
for (int t = v; t != z; t = parent[0][t]) {
right.push_back(value[t]);
}
reverse(right.begin(), right.end());
for (auto t : right) {
left.push_back(t);
}
right.clear();
for (auto c : s) {
right.push_back(c - 'a' + 1);
}
answer[i] = match(left, right);
if (x != u) {
hash_t hash(0, 0);
for (int t = right.size() - 1; ~t; --t) {
hash = hash * base + right[t];
}
event[l].emplace_back(x, make_pair(hash.get(), i));
event[l].emplace_back(u, make_pair(hash.get(), i + q));
}
if (y != v) {
hash_t hash(0, 0);
for (int t = 0; t < right.size(); ++t) {
hash = hash * base + right[t];
}
event[l].emplace_back(y, make_pair(hash.get(), i));
event[l].emplace_back(v, make_pair(hash.get(), i + q));
}
}
auto get_hash = [&](int x, int y) {
return (hash[x] - hash[y] * power[depth[x] - depth[y]]).get();
};
for (int i = 1; i <= m; ++i) {
if (!event[i].empty()) {
vector<vector<pair<long long, int>>> queries(n);
for (auto e : event[i]) {
queries[e.first].push_back(e.second);
}
unordered_map<long long, int> appear;
function<void(int)> solve = [&](int x) {
if (~jump[i][x]) {
++appear[get_hash(x, jump[i][x])];
}
for (auto e : queries[x]) {
if (e.second < q) {
answer[e.second] += appear[e.first];
} else {
answer[e.second - q] -= appear[e.first];
}
}
for (auto e : adj[x]) {
if (e.first != parent[0][x]) {
solve(e.first);
}
}
if (~jump[i][x]) {
--appear[get_hash(x, jump[i][x])];
}
};
solve(0);
}
}
for (int i = 0; i < q; ++i) {
printf("%d\n", answer[i]);
}
return 0;
}