Cakey McCakeFace
模拟。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
vector<int> a(n), b(m);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 0; i < m; ++i) {
scanf("%d", &b[i]);
}
map<int, int> number;
for (auto x : a) {
for (auto y : b) {
if (x <= y) {
++number[y - x];
}
}
}
int best = 0, answer = -1;
for (auto p : number) {
if (answer < p.second) {
answer = p.second;
best = p.first;
}
}
printf("%d\n", best);
return 0;
}
Table
枚举下边界,维护上边界的单调栈,考虑每个元素退栈的时候带来的影响,对 y y 差分一次,对 差分两次之后影响的位置只有 O(1) O ( 1 ) 个,直接打标记就行了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m, k, q, top, s[N], up[N], a[N][N], answer[N][N];
int add(int l, int r, int x, int y) {
++answer[y][x - r + 1];
++answer[y][r - l];
--answer[y][x - l + 1];
--answer[y][1];
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
scanf("%d %d %d %d", &n, &m, &k, &q);
while (k--) {
int xl, xr, yl, yr;
scanf("%d %d %d %d", &xl, &xr, &yl, &yr);
++a[xr][yr];
++a[xl][yl];
--a[xl][yr];
--a[xr][yl];
}
for (int i = n; i; --i) {
for (int j = m; j; --j) {
a[i][j] += a[i + 1][j] + a[i][j + 1] - a[i + 1][j + 1];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i][j]) {
up[j] = 0;
} else {
++up[j];
}
}
top = 0;
for (int j = 1; j <= m; ++j) {
while (top && up[s[top]] > up[j]) {
add(s[top - 1], s[top], j - 1, up[s[top]]);
top--;
}
s[++top] = j;
}
while (top) {
add(s[top - 1], s[top], m, up[s[top]]);
top--;
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m + 1; ++j) {
answer[i][j] += answer[i][j - 1];
}
}
for (int i = n; i; --i) {
for (int j = m; j; --j) {
answer[i][j] += answer[i + 1][j] + answer[i][j + 1] - answer[i + 1][j + 1];
}
}
while (q--) {
int x, y;
scanf("%d %d", &x, &y);
printf("%d\n", answer[x][y]);
}
return 0;
}
Macarons
状压,矩阵快速幂。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 260;
const int mod = 1e9;
int n, f[N], g[N];
ll m;
int add(int x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
return x;
}
int mul(int x, int y) {
return (ll)x * y % mod;
}
struct matrix_t {
int a[N][N];
matrix_t() {
for (int i = 0; i < 1 << n; ++i) {
for (int j = 0; j < 1 << n; ++j) {
a[i][j] = 0;
}
}
}
matrix_t operator * (const matrix_t &b) const {
matrix_t c;
for (int k = 0; k < 1 << n; ++k) {
for (int i = 0; i < 1 << n; ++i) {
if (a[i][k]) {
for (int j = 0; j < 1 << n; ++j) {
if (b.a[k][j]) {
c.a[i][j] = add(c.a[i][j], mul(a[i][k], b.a[k][j]));
}
}
}
}
}
return c;
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
scanf("%d %lld", &n, &m);
matrix_t base, answer;
for (int i = 0; i < 1 << n; ++i) {
answer.a[i][i] = 1;
}
for (int s = 0; s < 1 << n; ++s) {
f[s] = 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 1 << n; ++j) {
if (!(j >> i & 1)) {
g[j | 1 << i] = add(g[j | 1 << i], f[j]);
} else {
g[j ^ 1 << i] = add(g[j ^ 1 << i], f[j]);
g[j] = add(g[j], f[j]);
if (i && !(j >> i - 1 & 1)) {
g[j | 1 << i - 1] = add(g[j | 1 << i - 1], f[j]);
}
}
}
for (int j = 0; j < 1 << n; ++j) {
f[j] = g[j];
g[j] = 0;
}
}
for (int i = 0; i < 1 << n; ++i) {
base.a[s][i] = f[i];
f[i] = 0;
}
}
for (; m; m >>= 1, base = base * base) {
if (m & 1) {
answer = answer * base;
}
}
printf("%d\n", answer.a[(1 << n) - 1][(1 << n) - 1]);
return 0;
}
Candy Chain
记 f(i,j) f ( i , j ) 表示消去区间 [i,j] [ i , j ] 的最大收益, g(i,j,k) g ( i , j , k ) 表示考虑区间 [i,j] [ i , j ] ,当前在trie树上 k k 节点的最大收益,转移要么跳过一段被消掉的区间,要么往下走,要么将这一段卖掉走到根。合法状态并不多,直接转移就可以。
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
const int M = 20005;
int n, m, root, total, answer[N], value[M], f[N][N], trans[M][26], g[N][M];
char s[N], t[N];
int new_node() {
++total;
value[total] = -1;
return total;
}
void insert(int v) {
int x = root;
for (int i = 0; t[i]; ++i) {
if (!trans[x][t[i] - 'a']) {
trans[x][t[i] - 'a'] = new_node();
}
x = trans[x][t[i] - 'a'];
}
value[x] = max(value[x], v);
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
scanf("%s", s + 1);
n = strlen(s + 1);
root = new_node();
scanf("%d", &m);
while (m--) {
int v;
scanf("%s %d", t, &v);
insert(v);
reverse(t, t + strlen(t));
insert(v);
}
memset(f, -1, sizeof f);
for (int i = n; i; --i) {
for (int j = i - 1; j <= n; ++j) {
for (int k = 1; k <= total; ++k) {
g[j][k] = -1;
}
}
g[i - 1][root] = 0;
for (int j = i - 1; j <= n; ++j) {
for (int k = 1; k <= total; ++k) {
if (~g[j][k]) {
for (int l = j + 1; l <= n; ++l) {
if (~f[j + 1][l]) {
g[l][k] = max(g[l][k], g[j][k] + f[j + 1][l]);
}
}
if (j < n) {
if (trans[k][s[j + 1] - 'a']) {
g[j + 1][trans[k][s[j + 1] - 'a']] = max(g[j + 1][trans[k][s[j + 1] - 'a']], g[j][k]);
if (~value[trans[k][s[j + 1] - 'a']]) {
g[j + 1][root] = max(g[j + 1][root], g[j][k] + value[trans[k][s[j + 1] - 'a']]);
}
}
}
if (k == root) {
f[i][j] = max(f[i][j], g[j][k]);
}
}
}
}
}
for (int i = 1; i <= n; ++i) {
answer[i] = answer[i - 1];
for (int j = 1; j <= i; ++j) {
if (~f[j][i]) {
answer[i] = max(answer[i], answer[j - 1] + f[j][i]);
}
}
}
printf("%d\n", answer[n]);
return 0;
}
Ingredients
模拟。
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
const int inf = 0x3f3f3f3f;
int n, m, total, f[N], cost[N], value[N];
vector<pair<int, pair<int, int>>> adj[N];
map<string, int> id;
bool visit[N];
void dfs(int x) {
visit[x] = true;
if (adj[x].empty()) {
return;
}
cost[x] = inf;
value[x] = -inf;
for (auto e : adj[x]) {
int y = e.first, u = e.second.first, v = e.second.second;
if (!visit[y]) {
dfs(y);
}
if (cost[x] > cost[y] + u || (cost[x] == cost[y] + u && value[x] < value[y] + v)) {
cost[x] = cost[y] + u;
value[x] = value[y] + v;
}
}
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
cin >> m >> n;
while (n--) {
string from, to, temp;
int cost, value;
cin >> to >> from >> temp >> cost >> value;
if (id.find(to) == id.end()) {
id[to] = ++total;
}
if (id.find(from) == id.end()) {
id[from] = ++total;
}
adj[id[to]].push_back(make_pair(id[from], make_pair(cost, value)));
}
for (int i = 1; i <= total; ++i) {
if (!visit[i]) {
dfs(i);
}
}
for (int i = 1; i <= m; ++i) {
f[i] = -inf;
}
for (int i = 1; i <= total; ++i) {
for (int j = m; j >= cost[i]; --j) {
f[j] = max(f[j], f[j - cost[i]] + value[i]);
}
}
int answer = 0, best = 0;
for (int i = 1; i <= m; ++i) {
if (f[i] > answer) {
answer = f[i];
best = i;
}
}
cout << answer << endl << best << endl;
return 0;
}
Shattered Cake
答案是总面积除以宽。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int w, n;
scanf("%d %d", &w, &n);
int sum = 0;
while (n--) {
int x, y;
scanf("%d %d", &x, &y);
sum += x * y;
}
printf("%d\n", sum / w);
return 0;
}
Cordon Bleu
在餐馆新建 个点表示从餐馆出发的人,然后跑KM。
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m, answer, visit_t, l[N], r[N], lx[N], ly[N], dist[N], visit[N], parent[N], a[N][N];
pair<int, int> restaurant, bottle[N], courier[N];
void km(int n) {
for (int i = 1; i <= n; ++i) {
lx[i] = a[i][1];
for (int j = 2; j <= n; ++j) {
lx[i] = min(lx[i], a[i][j]);
}
}
for (int i = 1; i <= n; ++i) {
ly[i] = a[1][i] - lx[1];
for (int j = 2; j <= n; ++j) {
ly[i] = min(ly[i], a[j][i] - lx[j]);
}
}
int t = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (!r[j] && lx[i] + ly[j] == a[i][j]) {
l[i] = j;
r[j] = i;
++t;
break;
}
}
}
for (; t <= n; ++t) {
int source = 0, sink;
for (int i = 1; i <= n; ++i) {
if (!l[i]) {
source = i;
break;
}
}
for (int i = 1; i <= n; ++i) {
dist[i] = a[source][i] - lx[source] - ly[i];
parent[i] = 0;
}
++visit_t;
while (true) {
sink = 0;
for (int j = 1; j <= n; ++j) {
if (visit[j] != visit_t && (!sink || dist[j] < dist[sink])) {
sink = j;
}
}
visit[sink] = visit_t;
if (!r[sink]) {
break;
}
int from = r[sink];
for (int j = 1; j <= n; ++j) {
if (visit[j] != visit_t) {
int diff = dist[sink] + (a[from][j] - lx[from] - ly[j]);
if (dist[j] > diff) {
dist[j] = diff;
parent[j] = sink;
}
}
}
}
for (int j = 1; j <= n; ++j) {
if (visit[j] == visit_t && j != sink) {
lx[r[j]] += dist[sink] - dist[j];
ly[j] -= dist[sink] - dist[j];
}
}
lx[source] += dist[sink];
while (parent[sink]) {
l[r[parent[sink]]] = sink;
r[sink] = r[parent[sink]];
sink = parent[sink];
}
l[source] = sink;
r[sink] = source;
}
for (int i = 1; i <= n; ++i) {
answer += a[i][l[i]];
}
}
int calc(pair<int, int> a, pair<int, int> b) {
return abs(a.first - b.first) + abs(a.second - b.second);
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%d %d", &bottle[i].first, &bottle[i].second);
}
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &courier[i].first, &courier[i].second);
}
scanf("%d %d", &restaurant.first, &restaurant.second);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n + m - 1; ++j) {
a[j][i] = calc(bottle[i], j <= m ? courier[j] : restaurant);
}
}
km(n + m - 1);
for (int i = 1; i <= n; ++i) {
answer += calc(bottle[i], restaurant);
}
printf("%d\n", answer);
return 0;
}
Kabobs
建出自动机,暴力搜出所有可能的在自动机上的位置集合,合法的状态并不多,暴力DP就行了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3000005;
const int mod = 1e7;
struct rule_t {
int mid, size;
string s;
rule_t(string from, string to) {
s = from + to;
mid = from.length();
size = s.length();
}
int go(int x, char c) {
if (s[x] == c) {
return (x + 1) % size;
} else if (x < mid) {
return c == s[0];
} else {
return (c == s[mid]) + mid;
}
}
};
int n, total, f[N], g[N];
vector<rule_t> limit;
string sigma, rules;
vector<int> adj[N];
map<ll, int> id;
ll realate[N];
int add(int x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
return x;
}
ll encode(vector<int> a) {
ll result = 0;
for (int i = 0; i < limit.size(); ++i) {
result = result * limit[i].size + a[i];
}
return result;
}
vector<int> decode(ll a) {
vector<int> result(limit.size());
for (int i = limit.size() - 1; ~i; --i) {
result[i] = a % limit[i].size;
a /= limit[i].size;
}
return result;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> sigma >> rules;
for (int i = 0; i < rules.length(); ++i) {
string from, to;
while (rules[i] != '>') {
from += rules[i++];
}
i++;
while (i < rules.length() && rules[i] != '|') {
to += rules[i++];
}
limit.push_back(rule_t(from, to));
}
id[0] = ++total;
realate[total] = 0;
for (int i = 1; i <= total; ++i) {
vector<int> current = decode(realate[i]);
for (auto c : sigma) {
vector<int> next = current;
for (int i = 0; i < limit.size(); ++i) {
next[i] = limit[i].go(next[i], c);
}
ll code = encode(next);
if (id.find(code) == id.end()) {
id[code] = ++total;
realate[total] = code;
}
adj[i].push_back(id[code]);
}
}
f[1] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= total; ++j) {
if (f[j]) {
for (auto k : adj[j]) {
g[k] = add(g[k], f[j]);
}
}
}
for (int j = 1; j <= total; ++j) {
f[j] = g[j];
g[j] = 0;
}
}
int answer = 0;
for (int i = 1; i <= total; ++i) {
vector<int> current = decode(realate[i]);
bool flag = true;
for (int j = 0; j < limit.size(); ++j) {
if (current[j] >= limit[j].mid) {
flag = false;
break;
}
}
if (flag) {
answer = add(answer, f[i]);
}
}
printf("%d\n", answer);
return 0;
}
Burglary
f(i,j,k) f ( i , j , k ) 表示考虑第 i i 层以下的,当前在楼梯 ,暴力转移。
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
const int M = 5005;
int n, m, l[M], r[M], sum[M], number[N], ladder[N][15], f[N][15][15];
char board[N][M];
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%s %s", board[i] + 1, board[i + 1] + 1);
for (int j = 1; j <= m; ++j) {
if (board[i + 1][j] == '|') {
ladder[i][++number[i]] = j;
}
}
}
for (int i = n + 1; i > 1; --i) {
l[0] = 1;
for (int j = 1; j <= m; ++j) {
l[j] = l[j - 1];
sum[j] = sum[j - 1];
if (isdigit(board[i][j])) {
l[j] = j;
sum[j] += board[i][j] - '0';
}
}
r[m + 1] = m;
for (int j = m; j; --j) {
r[j] = r[j + 1];
if (isdigit(board[i][j])) {
r[j] = j;
}
}
for (int j = 1; j <= number[i - 1]; ++j) {
for (int k = j; k <= number[i - 1]; ++k) {
int sl = ladder[i - 1][j], sr = ladder[i - 1][k];
f[i][j][k] = sum[r[sr]] - sum[l[sl] - 1];
if (i != n + 1 && (sl != sr || sum[sr] == sum[sr - 1])) {
for (int a = 1; a <= number[i]; ++a) {
for (int b = a; b <= number[i]; ++b) {
int tl = ladder[i][a], tr = ladder[i][b];
if (tl != tr || sum[tr] == sum[tr - 1]) {
if (sr <= tl) {
if (sum[tl] == sum[sr - 1]) {
f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[tr]] - sum[l[sl] - 1]);
}
} else if (sl >= tr) {
if (sum[sl] == sum[tr - 1]) {
f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[sr]] - sum[l[tl] - 1]);
}
} else if (l[min(sr, tr)] <= r[max(sl, tl)]) {
f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[max(sr, tr)]] - sum[l[min(sl, tl)] - 1]);
} else {
f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[max(sr, tr)]] - sum[l[min(sr, tr)] - 1] + sum[r[max(sl, tl)]] - sum[l[min(sl, tl)] - 1]);
}
}
}
}
}
}
}
}
int answer = 0;
for (int i = 1; i <= number[1]; ++i) {
for (int j = i; j <= number[1]; ++j) {
answer = max(answer, f[2][i][j]);
}
}
printf("%d\n", answer);
return 0;
}
Frosting on the Cake
模拟。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
vector<int> a(3, 0), b(3, 0);
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
int x;
scanf("%d", &x);
a[i % 3] += x;
}
for (int i = 1; i <= n; ++i) {
int x;
scanf("%d", &x);
b[i % 3] += x;
}
for (int i = 0; i < 3; ++i) {
ll answer = 0;
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
if ((j + k) % 3 == i) {
answer += (ll)a[j] * b[k];
}
}
}
printf("%lld%c", answer, i == 2 ? '\n' : ' ');
}
return 0;
}
Blowing Candles
旋转卡壳。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 200005;
const ld inf = 1e9;
struct point_t {
int x, y;
point_t(int x = 0, int y = 0):x(x), y(y) {
}
point_t operator + (const point_t &b) const {
return point_t(x + b.x, y + b.y);
}
point_t operator - (const point_t &b) const {
return point_t(x - b.x, y - b.y);
}
bool operator < (const point_t &b) const {
return x < b.x || (x == b.x && y < b.y);
}
ll operator * (const point_t &b) const {
return (ll)x * b.y - (ll)y * b.x;
}
} p[N], lower[N], upper[N], convex[N];
int n, m, upper_m, lower_m;
ld dist(point_t p, point_t q) {
return sqrtl((ll)(p.x - q.x) * (p.x - q.x) + (ll)(p.y - q.y) * (p.y - q.y));
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%d %d", &p[i].x, &p[i].y);
}
sort(p + 1, p + n + 1);
for (int i = 1; i <= n; ++i) {
while (lower_m > 1 && (p[i] - lower[lower_m - 1]) * (lower[lower_m] - lower[lower_m - 1]) >= 0) {
--lower_m;
}
lower[++lower_m] = p[i];
}
for (int i = 1; i <= n; ++i) {
while (upper_m > 1 && (p[i] - upper[upper_m - 1]) * (upper[upper_m] - upper[upper_m - 1]) <= 0) {
--upper_m;
}
upper[++upper_m] = p[i];
}
m = 0;
for (int i = 1; i <= lower_m; ++i) {
convex[++m] = lower[i];
}
for (int i = upper_m - 1; i > 1; --i) {
convex[++m] = upper[i];
}
if (m == 2) {
puts("0");
} else {
convex[m + 1] = convex[1];
ld answer = inf;
for (int i = 1, j = 2; i <= m; ++i) {
while ((convex[i + 1] - convex[i]) * (convex[j + 1] - convex[i]) > (convex[i + 1] - convex[i]) * (convex[j] - convex[i])) {
j = j % m + 1;
}
answer = min(answer, (convex[i + 1] - convex[i]) * (convex[j] - convex[i]) / dist(convex[i], convex[i + 1]));
}
printf("%.8lf\n", (double)answer);
}
return 0;
}