版权声明:本文为博主原创文章,在标注作者的情况下可自由转载。 https://blog.csdn.net/EI_Captain/article/details/88208333
如果没有悲伤 世界是否还会美丽?
你的路往南走 我的心往北去
——幼稚园杀手《悲情城市 2017》
A String Reconstruction
开一个队列,在扫动的时候惰性检查对首是否能管住我再扔掉就行了。复杂度线性。
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <limits>
#include <functional>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <queue>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
const int L = 2000010, N = 100010;
int n, l;
vector<int> tag[L];
int ll[N];
char* pos[N];
char s[L], sv[L];
int main() {
scanf("%d", &n);
char* p = sv;
for (int i = 1; i <= n; ++i) {
scanf(" %s", p);
pos[i] = p;
int len = strlen(p);
ll[i] = len;
p += len + 1;
int c;
scanf("%d", &c);
while (c--) {
int t;
scanf("%d", &t);
tag[t].push_back(i);
l = max(l, t + len - 1);
}
}
queue<pair<int, int>> q;
for (int i = 1; i <= l; ++i) {
for (const auto& v : tag[i])
q.push(make_pair(i + ll[v] - 1, v));
while (!q.empty() && q.front().first < i)
q.pop();
if (q.empty())
s[i] = 'a';
else {
int ed = q.front().first, v = q.front().second;
s[i] = pos[v][ll[v] - (ed - i) - 1];
}
}
puts(s + 1);
}
B Highroads
建成各深度尽量相同的菊花图,讨论一下就行。复杂度线性。
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <limits>
#include <functional>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <queue>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
int main() {
int n, k;
scanf("%d%d", &n, &k);
int v = n - 1;
int l = v / k, b = v % k, a = k - b;
if (b == 0) {
printf("%d\n", l * 2);
} else if (b == 1)
printf("%d\n", l * 2 + 1);
else
printf("%d\n", l * 2 + 2);
int cnt = 1;
while (a--) {
printf("%d %d\n", 1, ++cnt);
for (int rep = 1; rep < l; ++rep) {
int cur = cnt;
printf("%d %d\n", cur, ++cnt);
}
}
while (b--) {
printf("%d %d\n", 1, ++cnt);
for (int rep = 1; rep <= l; ++rep) {
int cur = cnt;
printf("%d %d\n", cur, ++cnt);
}
}
return 0;
}
C DNA Evolution
按同余字符串长度分类,树状数组即可维护。时间 ,空间 。
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <limits>
#include <functional>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <queue>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
const int N = 101000, L = 11;
int lowBit(int k) {
return k & -k;
}
void ch(int* fw, int n, int k, int x) {
for (; k <= n; k += lowBit(k))
fw[k] += x;
}
int qry(int* fw, int k) {
int ret = 0;
for (; k; k -= lowBit(k))
ret += fw[k];
return ret;
}
char* key = "ATGC";
int n;
char s[N], tmp[L];
int mp[256];
int fw[L][4][N];
void apply(int k, int v, int x) {
for (int mod = 1; mod < L; ++mod) {
ch(fw[mod][v] + (k % mod) * (n / mod + 3), n / mod + 1, (k - 1) / mod + 1, x);
}
}
int qry(int mod, int v, int res, int r) {
if (res == 0)
res = mod;
int p = (r - res + mod) / mod;
res %= mod;
return qry(fw[mod][v] + res * (n / mod + 3), p);
}
int main() {
for (int i = 0; i < 4; ++i)
mp[key[i]] = i;
scanf("%s", s + 1);
n = strlen(s + 1);
for (int i = 1; i <= n; ++i)
apply(i, mp[s[i]], 1);
int q;
scanf("%d", &q);
while (q--) {
int opt, x, y;
scanf("%d%d", &opt, &x);
if (opt == 1) {
char c;
scanf(" %c", &c);
apply(x, mp[s[x]], -1);
apply(x, mp[s[x] = c], 1);
} else {
scanf("%d%s", &y, tmp);
int m = strlen(tmp);
int ans = 0;
for (int i = 0; i < m; ++i) {
int r = (x + i) % m;
ans += qry(m, mp[tmp[i]], r, y) - qry(m, mp[tmp[i]], r, x - 1);
}
printf("%d\n", ans);
}
}
}
D Best Edge Weight
随便找一颗 MST,在树外的边答案就是在 MST 上两点经过 ,树边的答案由树上路径经过它的树外边的最小值给出。前者倍增直接找,后者可以把边按 排序后用并查集来快速修改。时间复杂度 。
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <limits>
#include <functional>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <queue>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
struct E {
int v, w;
E* next;
};
struct Nde {
int u, v, w, id;
bool operator<(const Nde& rhs) const {
return w < rhs.w;
}
};
const int N = 200010, L = 18;
int n, m;
int prt[N][L], mx[N][L];
int val[N];
int ans[N], f[N], dep[N];
bool vis[N];
Nde ed[N];
E* g[N];
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
void adde(int u, int v, int w);
void dfs(int u);
pair<int, int> qry(int u, int v);
void flush(int u, int d, int w);
int main() {
scanf("%d%d", &n, &m);
iota(f + 1, f + n + 1, 1);
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &ed[i].u, &ed[i].v, &ed[i].w);
ed[i].id = i;
}
sort(ed + 1, ed + m + 1);
for (int i = 1; i <= m; ++i) {
int x = find(ed[i].u), y = find(ed[i].v);
if (x != y) {
f[x] = y;
adde(ed[i].u, ed[i].v, ed[i].w);
adde(ed[i].v, ed[i].u, ed[i].w);
}
}
dfs(1);
iota(f + 1, f + n + 1, 1);
for (int i = 1; i <= m; ++i) {
if (prt[ed[i].u][0] == ed[i].v || prt[ed[i].v][0] == ed[i].u)
continue;
int lca, cans;
tie(cans, lca) = qry(ed[i].u, ed[i].v);
ans[ed[i].id] = cans - 1;
flush(ed[i].u, dep[lca], ed[i].w);
flush(ed[i].v, dep[lca], ed[i].w);
}
for (int i = 1; i <= m; ++i)
if (prt[ed[i].u][0] == ed[i].v || prt[ed[i].v][0] == ed[i].u) {
int u = ed[i].u, v = ed[i].v;
if (prt[u][0] == v)
swap(u, v);
ans[ed[i].id] = val[v] - 1;
}
for (int i = 1; i <= m; ++i)
printf("%d ", ans[i]);
return 0;
}
void flush(int u, int d, int w) {
u = find(u);
while (dep[u] > d) {
val[u] = w;
f[u] = prt[u][0];
u = find(u);
}
}
pair<int, int> qry(int u, int v) {
int ret = 0;
if (dep[u] < dep[v])
swap(u, v);
for (int k = L - 1; k >= 0; --k)
if ((dep[u] - dep[v]) >> k & 1) {
ret = max(ret, mx[u][k]);
u = prt[u][k];
}
if (u == v)
return make_pair(ret, u);
for (int k = L - 1; k >= 0; --k)
if (prt[u][k] != prt[v][k]) {
ret = max({ret, mx[u][k], mx[v][k]});
u = prt[u][k];
v = prt[v][k];
}
return make_pair(max({ret, mx[u][0], mx[v][0]}), prt[u][0]);
}
void dfs(int u) {
vis[u] = true;
for (int i = 1; i < L; ++i) {
prt[u][i] = prt[prt[u][i - 1]][i - 1];
mx[u][i] = max(mx[u][i - 1], mx[prt[u][i - 1]][i - 1]);
}
for (E* p = g[u]; p; p = p->next)
if (!vis[p->v]) {
dep[p->v] = dep[u] + 1;
prt[p->v][0] = u;
mx[p->v][0] = p->w;
dfs(p->v);
}
}
void adde(int u, int v, int w) {
static E pool[N * 2];
static E* p = pool;
p->v = v;
p->w = w;
p->next = g[u];
g[u] = p;
++p;
}
E Rusty String
对答案造成阻碍的当一对 V
、K
的坐标为
时,显然它周期不可能是
的因子。于是就是一个翻转后的卷积。最后枚举倍数检查是否合法,总时间
。
#include <cstdio>
#include <cmath>
#include <cassert>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <limits>
#include <functional>
#include <stack>
#include <vector>
#include <complex>
#include <set>
#include <map>
#include <queue>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
const int L = 21;
const int P = 998244353, R = 3;
int a[1 << L], b[1 << L];
bool res[1 << L], ans[1 << L];
void ntt(int* arr, int lgn, bool inv);
int mpow(int a, int k);
void exGcd(int a, int b, int& x, int& y);
int rev(int a, int p = P);
char s[1 << L];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d%s", &n, s + 1);
int l = 1;
while ((1 << l) <= n)
++l;
++l;
memset(a, 0, sizeof(int) << l);
memset(b, 0, sizeof(int) << l);
memset(res, 0, sizeof(bool) << l);
for (int i = 1; i <= n; ++i) {
if (s[i] == 'V')
a[i - 1] = 1;
else if (s[i] == 'K')
b[n - i] = 1;
}
ntt(a, l, false);
ntt(b, l, false);
for (int i = 0; i < 1 << l; ++i)
a[i] = a[i] * (ll)b[i] % P;
ntt(a, l, true);
for (int i = 0; i < 1 << l; ++i)
if (a[i]) {
int delt = i - n + 1;
res[abs(delt)] = true;
}
for (int i = 1; i <= n; ++i) {
ans[i] = true;
for (int j = i; j < n; j += i)
if (res[j]) {
ans[i] = false;
break;
}
}
printf("%lu\n", count(ans + 1, ans + n + 1, true));
for (int i = 1; i <= n; ++i)
if (ans[i])
printf("%d ", i);
putchar('\n');
}
}
int mpow(int a, int k) {
int ret = 1;
while (k) {
if (k & 1)
ret = (ll)ret * a % P;
a = a * (ll)a % P;
k >>= 1;
}
return ret;
}
void exGcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1;
y = 0;
return;
}
exGcd(b, a % b, y, x);
y -= a / b * x;
}
int rev(int a, int p) {
int x, y;
exGcd(a, p, x, y);
if (x < 0)
x += p;
return x;
}
void ntt(int* arr, int lgn, bool inv) {
static int rev[1 << L];
int n = 1 << lgn;
for (int i = 1; i < n; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lgn - 1));
for (int i = 0; i < n; ++i)
if (i < rev[i])
swap(arr[i], arr[rev[i]]);
int rt = inv ? ::rev(R) : R;
for (int i = 0; i < lgn; ++i) {
int t = 1 << i, g = mpow(rt, (P - 1) >> (i + 1));
for (int j = 0; j < n; j += t << 1) {
int w = 1;
for (int k = j; k < j + t; ++k) {
int a0 = arr[k], a1 = arr[k + t];
arr[k] = (a0 + a1 * (ll)w) % P;
arr[k + t] = (a0 + a1 * (ll)(P - w)) % P;
w = w * (ll)g % P;
}
}
}
if (inv) {
int rm = ::rev(n);
for (int i = 0; i < n; ++i)
arr[i] = arr[i] * (ll)rm % P;
}
}
F Dirty Arkady’s Kitchen
注意到图是无向图,这意味着可以在一条边上来回走。特判一下 的情况,其余情况不关注某个点,而是关注某个点上可以来回走的连续时间段,这些段是由它的连边贡献的,因此总量是 ,对于距离的奇偶性拆点跑最短路。实现地精细一点保证每个时间段只被松弛一次,从而每条边只用于松弛 次。复杂度 。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <random>
#include <bitset>
#include <tuple>
#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;
struct Node {
int u, step;
Node(int u, int step) : u(u), step(step) {}
bool operator>(const Node& rhs) const { return step > rhs.step; }
};
const int N = 500010;
int n;
vector<tuple<int, int, int>> rg[N];
vector<int> hl[N][2], hr[N][2], dis[N][2];
vector<vector<tuple<int, int, int>>> adj[N][2];
void adde(int u, int v, int l, int r);
bool cmp(const tuple<int, int, int>& lhs, const tuple<int, int, int>& rhs) {
if (get<1>(lhs) != get<1>(rhs))
return get<1>(lhs) < get<1>(rhs);
return get<2>(lhs) < get<2>(rhs);
}
int main() {
int m;
scanf("%d%d", &n, &m);
while (m--) {
int u, v, l, r;
scanf("%d%d%d%d", &u, &v, &l, &r);
adde(u, v, l, r);
adde(v, u, l, r);
}
if (rg[1].empty()) {
puts(n == 1 ? "0" : "-1");
} else {
for (int i = 1; i <= n; ++i) {
sort(rg[i].begin(), rg[i].end(), cmp);
for (int j = 0; j < 2; ++j) {
for (const auto& tup : rg[i]) {
int l, r;
tie(ignore, l, r) = tup;
if ((l & 1) != j)
++l;
if ((r & 1) != j)
--r;
if (l > r)
continue;
if (hl[i][j].empty() || hr[i][j].back() < l) {
hl[i][j].push_back(l);
hr[i][j].push_back(r);
adj[i][j].push_back(vector<tuple<int, int, int>>(1, tup));
} else {
hr[i][j].back() = max(hr[i][j].back(), r);
adj[i][j].back().push_back(tup);
}
}
dis[i][j] = vector<int>(hl[i][j].size(), -1);
}
}
priority_queue<Node, vector<Node>, greater<Node>> q;
int ans = -1;
q.emplace(1, 0);
while (!q.empty()) {
Node tmp = q.top();
q.pop();
if (tmp.u == n) {
ans = tmp.step;
break;
}
int u = tmp.u, j = tmp.step & 1;
int i = int(upper_bound(hl[u][j].begin(), hl[u][j].end(), tmp.step) - hl[u][j].begin()) - 1;
if (i < 0 || hl[u][j][i] > tmp.step || dis[u][j][i] != -1 && (dis[u][j][i] <= tmp.step))
continue;
dis[u][j][i] = tmp.step;
for (const auto& tup : adj[u][j][i]) {
int v, l, r;
tie(v, l, r) = tup;
if (r <= tmp.step)
continue;
int dist;
if (l <= tmp.step)
dist = tmp.step + 1;
else {
dist = (l - tmp.step + 1) / 2 * 2 + tmp.step;
if (dist >= r)
continue;
++dist;
}
q.emplace(v, dist);
}
}
printf("%d\n", ans);
}
return 0;
}
void adde(int u, int v, int l, int r) {
rg[u].emplace_back(v, l, r);
}