Alice the Fan
预处理 f ( w i n a , w i n b , s c o r e a , s c o r e b ) f(win_a, win_b, score_a, score_b) f(wina,winb,scorea,scoreb) 表示这个状态能不能到达然后倒着输出方案就行了。
#include <bits/stdc++.h>
using namespace std;
const int N = 3;
const int MAX = 200;
const int FIRST = 25;
const int LAST = 15;
const int DIFF = 2;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
vector<vector<pair<int, int>>> dp((N + 1) * (N + 1), vector<pair<int, int>> ((MAX + 1) * (MAX + 1), make_pair(-1, -1)));
vector<pair<int, int>> a_win_first, a_win_last;
vector<pair<int, int>> b_win_first, b_win_last;
for (int i = 0; i <= MAX; ++i) {
for (int j = 0; j <= MAX; ++j) {
if (abs(i - j) == DIFF) {
if (max(i, j) >= FIRST) {
if (i > j) {
a_win_first.emplace_back(i, j);
} else {
b_win_first.emplace_back(i, j);
}
}
if (max(i, j) >= LAST) {
if (i > j) {
a_win_last.emplace_back(i, j);
} else {
b_win_last.emplace_back(i, j);
}
}
} else if (abs(i - j) > DIFF) {
if (max(i, j) == FIRST) {
if (i > j) {
a_win_first.emplace_back(i, j);
} else {
b_win_first.emplace_back(i, j);
}
}
if (max(i, j) == LAST) {
if (i > j) {
a_win_last.emplace_back(i, j);
} else {
b_win_last.emplace_back(i, j);
}
}
}
}
}
dp[0][0] = make_pair(0, 0);
for (int win_a = 0; win_a < N; ++win_a) {
for (int win_b = 0; win_b < N; ++win_b) {
for (int score_a = 0; score_a <= MAX; ++score_a) {
for (int score_b = 0; score_b <= MAX; ++score_b) {
if (~dp[win_a * (N + 1) + win_b][score_a * (MAX + 1) + score_b].first) {
vector<pair<int, int>> a_win = win_a == N - 1 && win_b == N - 1 ? a_win_last : a_win_first;
vector<pair<int, int>> b_win = win_a == N - 1 && win_b == N - 1 ? b_win_last : b_win_first;
for (auto p : a_win) {
int new_score_a = score_a + p.first;
int new_score_b = score_b + p.second;
if (new_score_a <= MAX && new_score_b <= MAX) {
int index_win = (win_a + 1) * (N + 1) + win_b;
int index_score = new_score_a * (MAX + 1) + new_score_b;
dp[index_win][index_score] = p;
}
}
for (auto p : b_win) {
int new_score_a = score_a + p.first;
int new_score_b = score_b + p.second;
if (new_score_a <= MAX && new_score_b <= MAX) {
int index_win = win_a * (N + 1) + (win_b + 1);
int index_score = new_score_a * (MAX + 1) + new_score_b;
dp[index_win][index_score] = p;
}
}
}
}
}
}
}
auto print = [&](int win_a, int win_b, int score_a, int score_b) {
vector<pair<int, int>> match;
printf("%d:%d\n", win_a, win_b);
while (win_a || win_b) {
pair<int, int> p = dp[win_a * (N + 1) + win_b][score_a * (MAX + 1) + score_b];
match.push_back(p);
if (p.first > p.second) {
--win_a;
} else {
--win_b;
}
score_a -= p.first;
score_b -= p.second;
}
for (int i = match.size() - 1; ~i; --i) {
printf("%d:%d%c", match[i].first, match[i].second, i ? ' ' : '\n');
}
};
auto solve = [&](int score_a, int score_b) {
for (int win_a = N; win_a <= N; ++win_a) {
for (int win_b = 0; win_b < N; ++win_b) {
if (~dp[win_a * (N + 1) + win_b][score_a * (MAX + 1) + score_b].first) {
print(win_a, win_b, score_a, score_b);
return;
}
}
}
for (int win_a = N - 1; ~win_a; --win_a) {
for (int win_b = N; win_b <= N; ++win_b) {
if (~dp[win_a * (N + 1) + win_b][score_a * (MAX + 1) + score_b].first) {
print(win_a, win_b, score_a, score_b);
return;
}
}
}
puts("Impossible");
};
int tt;
scanf("%d", &tt);
while (tt--) {
int score_a, score_b;
scanf("%d %d", &score_a, &score_b);
solve(score_a, score_b);
}
return 0;
}
Bimatching
假设需要匹配 2 2 2 个的点是 A A A 部点,对每个 A A A 部点拆点,并将拆之后的点连一条边,求一般图最大匹配减去 n n n 就是答案。
#include <bits/stdc++.h>
using namespace std;
class dsu_t {
public:
vector<int> p;
int n;
dsu_t(int n): n(n) {
p.resize(n);
for (int i = 0; i < n; ++i) {
p[i] = i;
}
}
inline int find(int x) {
while (x != p[x]) {
x = p[x] = p[p[x]];
}
return x;
}
inline bool unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
return false;
} else {
p[x] = y;
return true;
}
}
};
pair<int, vector<int>> max_matching(int n, vector<vector<int>> adj) {
vector<int> match(n, -1);
int answer = 0;
auto find_matching = [&](int start) {
vector<int> color(n, -1);
vector<int> prev(n, -1);
vector<int> visit(n);
queue<int> q;
int tt = 0;
dsu_t dsu(n);
q.push(start);
color[start] = 0;
auto lca = [&](int x, int y) {
++tt;
x = dsu.find(x);
y = dsu.find(y);
while (true) {
if (~x) {
if (visit[x] == tt) {
return x;
}
visit[x] = tt;
if (~match[x]) {
x = dsu.find(prev[match[x]]);
} else {
x = -1;
}
}
swap(x, y);
}
};
auto blossom = [&](int x, int y, int z) {
while (dsu.find(x) != z) {
prev[x] = y;
if (color[match[x]] == 1) {
q.push(match[x]);
color[match[x]] = 0;
}
if (dsu.find(x) == x) {
dsu.unite(x, z);
}
if (dsu.find(match[x]) == match[x]) {
dsu.unite(match[x], z);
}
y = match[x];
x = prev[y];
}
};
while (!q.empty()) {
int x = q.front();
q.pop();
for (auto y : adj[x]) {
if (!~color[y]) {
color[y] = 1;
prev[y] = x;
if (!~match[y]) {
while (~x) {
int last = match[x];
match[x] = y;
match[y] = x;
if (~last) {
y = last;
x = prev[y];
} else {
break;
}
}
return true;
} else {
q.push(match[y]);
color[match[y]] = 0;
}
} else if (!color[y] && dsu.find(x) != dsu.find(y)) {
int z = lca(x, y);
blossom(x, y, z);
blossom(y, x, z);
}
}
}
return false;
};
for (int i = 0; i < n; ++i) {
if (!~match[i] && find_matching(i)) {
++answer;
}
}
return make_pair(answer, match);
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
cin >> tt;
while (tt--) {
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n * 2 + m);
for (int i = 0; i < n; ++i) {
adj[i].push_back(i + n);
adj[i + n].push_back(i);
string s;
cin >> s;
for (int j = 0; j < m; ++j) {
if (s[j] == '1') {
adj[i].push_back(j + n * 2);
adj[j + n * 2].push_back(i);
adj[i + n].push_back(j + n * 2);
adj[j + n * 2].push_back(i + n);
}
}
}
printf("%d\n", max_matching(n * 2 + m, adj).first - n);
}
return 0;
}
Cactus Search
预处理两两最短路,每次选择一个最优的使候选点数最小的点询问即可,每次候选点数至少会变成原来的一半。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> dist(n, vector<int> (n, n));
vector<vector<int>> adj(n);
for (int i = 0; i < n; ++i) {
dist[i][i] = 0;
}
while (m--) {
int l;
cin >> l;
int last = -1;
while (l--) {
int x;
cin >> x;
--x;
if (~last) {
adj[last].push_back(x);
adj[x].push_back(last);
dist[x][last] = dist[last][x] = 1;
}
last = x;
}
}
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
for (int tt = 0; tt < n; ++tt) {
vector<int> candidates(n);
for (int i = 0; i < n; ++i) {
candidates.push_back(i);
}
while (true) {
int root = -1;
int remain = n;
for (int x = 0; x < n; ++x) {
int most = 0;
for (auto y : adj[x]) {
int current = 0;
for (auto z : candidates) {
if (dist[x][z] > dist[y][z]) {
++current;
}
}
most = max(most, current);
}
if (remain > most) {
remain = most;
root = x;
}
}
cout << root + 1 << endl;
string type;
cin >> type;
if (type == "FOUND") {
break;
}
int result;
cin >> result;
--result;
vector<int> new_candidates;
for (auto x : candidates) {
if (dist[root][x] > dist[result][x]) {
new_candidates.push_back(x);
}
}
swap(candidates, new_candidates);
}
}
return 0;
}
Distance Sum
特判树的情况,将所有度数为 1 1 1 的点全部缩掉,将度数大于 2 2 2 的点设为关键点,在关键点之间跑最短路,然后枚举两条边计算贡献即可。
#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<set<int>> graph(n);
for (int i = 0; i < m; ++i) {
int x, y;
scanf("%d %d", &x, &y);
--x;
--y;
graph[x].insert(y);
graph[y].insert(x);
}
set<pair<int, int>> degrees;
vector<int> weight(n, 1);
long long answer = 0;
for (int i = 0; i < n; ++i) {
degrees.insert(make_pair(graph[i].size(), i));
}
while (degrees.size() > 1) {
int x = degrees.begin()->second;
if (graph[x].size() > 1) {
break;
}
int y = *graph[x].begin();
degrees.erase(make_pair(graph[x].size(), x));
degrees.erase(make_pair(graph[y].size(), y));
graph[x].erase(y);
graph[y].erase(x);
answer += 2ll * weight[x] * (n - weight[x]);
weight[y] += weight[x];
degrees.insert(make_pair(graph[y].size(), y));
}
if (degrees.size() == 1) {
printf("%lld\n", answer >> 1);
return 0;
}
vector<int> id(n, -1);
vector<vector<int>> adj(n);
m = 0;
for (int x = 0; x < n; ++x) {
for (auto y : graph[x]) {
adj[x].push_back(y);
}
if (adj[x].size() > 2) {
id[x] = m++;
}
}
if (!m) {
for (int i = 0; i < n; ++i) {
if (adj[i].size() == 2) {
id[i] = m++;
break;
}
}
}
vector<vector<vector<vector<int>>>> between(m, vector<vector<vector<int>>> (m));
for (int x = 0; x < n; ++x) {
if (~id[x]) {
for (auto y : adj[x]) {
if (~id[y]) {
between[id[x]][id[y]].emplace_back();
}
}
}
}
for (int i = 0; i < n; ++i) {
if (adj[i].size() == 2 && !~id[i]) {
vector<int> weights(1, weight[i]);
vector<int> end(2);
id[i] = m;
for (int j = 0; j < 2; ++j) {
int x = adj[i][j], prev = i;
while (!~id[x]) {
weights.push_back(weight[x]);
id[x] = m;
int next = adj[x][0] + adj[x][1] - prev;
prev = x;
x = next;
}
end[j] = x;
reverse(weights.begin(), weights.end());
}
between[id[end[1]]][id[end[0]]].push_back(weights);
}
}
{
vector<int> new_weight(m);
for (int i = 0; i < n; ++i) {
if (id[i] != -1 && id[i] < m) {
new_weight[id[i]] = weight[i];
}
}
weight = new_weight;
}
vector<vector<int>> dist(m, vector<int> (m, n));
for (int i = 0; i < m; ++i) {
dist[i][i] = 0;
}
vector<pair<int, int>> non_empty;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
for (auto &p : between[i][j]) {
dist[i][j] = dist[j][i] = min(dist[i][j], (int)p.size() + 1);
}
if (!between[i][j].empty()) {
non_empty.emplace_back(i, j);
}
}
}
for (int k = 0; k < m; ++k) {
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < i; ++j) {
answer += 2ll * weight[i] * weight[j] * dist[i][j];
}
}
vector<vector<vector<vector<long long>>>> sum_weight(m, vector<vector<vector<long long>>> (m));
vector<vector<vector<vector<long long>>>> sum_dist(m, vector<vector<vector<long long>>> (m));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
sum_weight[i][j].resize(between[i][j].size());
sum_dist[i][j].resize(between[i][j].size());
for (int k = 0; k < between[i][j].size(); ++k) {
sum_weight[i][j][k].resize(between[i][j][k].size() + 1);
sum_dist[i][j][k].resize(between[i][j][k].size() + 1);
for (int l = 0; l < between[i][j][k].size(); ++l) {
sum_weight[i][j][k][l + 1] = sum_weight[i][j][k][l] + between[i][j][k][l];
sum_dist[i][j][k][l + 1] = sum_dist[i][j][k][l] + (long long)between[i][j][k][l] * l;
}
}
}
}
auto solve = [&](int i, int j, int k, int l, int r, int dist, int diff) {
return dist * (sum_weight[i][j][k][r] - sum_weight[i][j][k][l]) + diff * (sum_dist[i][j][k][r] - sum_dist[i][j][k][l]);
};
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
for (int k = 0; k < between[i][j].size(); ++k) {
for (int l = 0; l < between[i][j][k].size(); ++l) {
long long w = between[i][j][k][l];
for (int ii = 0; ii < m; ++ii) {
answer += 2ll * w * weight[ii] * min(dist[i][ii] + l + 1, dist[j][ii] + (int)between[i][j][k].size() - l);
}
for (auto p : non_empty) {
int ii = p.first;
int jj = p.second;
for (int kk = 0; kk < between[ii][jj].size(); ++kk) {
if (i == ii && j == jj && k == kk) {
{
int inside = l;
int outside = dist[i][j] + between[i][j][k].size() - l + 1;
if (inside <= outside) {
answer += w * solve(i, j, k, 0, l, inside, -1);
} else {
int ll = inside - outside + 1 >> 1;
answer += w * solve(i, j, k, 0, ll, outside, 1);
answer += w * solve(i, j, k, ll, l, inside, -1);
}
}
{
int inside = -l;
int outside = dist[i][j] + between[i][j][k].size() + l + 1;
int ll = min((int)between[i][j][k].size(), outside - inside + 1 >> 1);
answer += w * solve(i, j, k, l, ll, inside, 1);
answer += w * solve(i, j, k, ll, between[i][j][k].size(), outside, -1);
}
} else {
int to_ii = min(dist[i][ii] + l + 1, dist[j][ii] + (int)between[i][j][k].size() - l);
int to_jj = min(dist[i][jj] + l + 1, dist[j][jj] + (int)between[i][j][k].size() - l);
int ll = min(between[ii][jj][kk].size(), to_jj - to_ii + between[ii][jj][kk].size() + 1 >> 1);
answer += w * solve(ii, jj, kk, 0, ll, to_ii + 1, 1);
answer += w * solve(ii, jj, kk, ll, between[ii][jj][kk].size(), to_jj + between[ii][jj][kk].size(), -1);
}
}
}
}
}
}
}
printf("%lld\n", answer >> 1);
return 0;
}
Easy Chess
在前 7 7 7 行不以最后一列结尾,随便构造一下就行了。
#include <bits/stdc++.h>
using namespace std;
const int N = 8;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
n -= 2;
vector<int> a(N);
a[0] = 1;
a[N - 1] = 2;
while (n) {
for (int i = 0; i < N; ++i) {
if (a[i] < N) {
++a[i];
break;
}
}
--n;
}
int column = 0;
vector<pair<int, int>> answer;
for (int i = 0; i < N; ++i) {
if (a[i]) {
answer.emplace_back(i, column);
--a[i];
if (a[i] == N - 1) {
if (i == N - 1) {
for (int j = 0; j < N; ++j) {
if (j != column) {
answer.emplace_back(i, j);
}
}
} else {
for (int j = N - 1; ~j; --j) {
if (j != column) {
answer.emplace_back(i, j);
}
}
column = !column;
}
} else {
if (i == N - 1) {
for (int j = 0; j < N && a[i] > 1; ++j) {
if (j != column) {
answer.emplace_back(i, j);
--a[i];
}
}
answer.emplace_back(i, N - 1);
} else {
for (int j = 0; j < N && a[i]; ++j) {
if (j != column) {
answer.emplace_back(i, j);
--a[i];
if (!a[i]) {
column = j;
}
}
}
}
}
}
}
for (int i = 0; i < answer.size(); ++i) {
printf("%c%d%c", answer[i].first + 'a', answer[i].second + 1, i == answer.size() - 1 ? '\n' : ' ');
}
return 0;
}
Fractions
如果 n n n 是 p k p^k pk ,那么无解,否则考虑 n = x y ( gcd ( x , y ) = 1 ) n=xy(\gcd(x,y)=1) n=xy(gcd(x,y)=1) ,用 a x + b y = n − 1 n \frac{a}{x}+\frac{b}{y}=\frac{n-1}{n} xa+yb=nn−1 构造解,容易证明一定有解。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
for (int i = 2; i * i < n; ++i) {
if (n % i == 0 && __gcd(i, n / i) == 1) {
int x = i, y = n / i;
for (int a = 1; a < x; ++a) {
if ((n - 1 - a * y) % x == 0) {
int b = (n - 1 - a * y) / x;
puts("YES");
puts("2");
printf("%d %d\n", a, x);
printf("%d %d\n", b, y);
return 0;
}
}
}
}
puts("NO");
return 0;
}
Guest Student
暴力枚举起始位置算即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 7;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
vector<int> a(N);
int n;
scanf("%d", &n);
int each = 0;
for (int i = 0; i < N; ++i) {
scanf("%d", &a[i]);
each += a[i];
}
int week = (n - 1) / each;
int answer = N;
for (int i = 0; i < N; ++i) {
int remain = n - week * each;
for (int j = 1; j <= N; ++j) {
if (a[(i + j) % N]) {
--remain;
if (!remain) {
answer = min(answer, j);
break;
}
}
}
}
printf("%d\n", week * N + answer);
}
return 0;
}
Harder Satisfiability
建出2-SAT,不合法当且仅当满足下面某个条件:
- 2-SAT无解。
- 存在 i < j i<j i<j , i i i 是 ∃ \exist ∃ , j j j 是 ∀ \forall ∀ ,并且 i i i 和 j j j 在同一个强连通分量里。
- 存在两个点 i , j i, j i,j 都是 ∀ \forall ∀ ,且它们一个可以到达另一个。
显然不满足任意一个时是不合法的,否则可以用类似2-SAT的构造求出解。
#include <bits/stdc++.h>
using namespace std;
bool solve() {
int n, m;
cin >> n >> m;
string s;
cin >> s;
vector<int> from(m), to(m);
for (int i = 0; i < m; ++i) {
int x, y;
cin >> x >> y;
if (x < 0) {
x = n - x;
}
if (y < 0) {
y = n - y;
}
--x;
--y;
from[i] = x;
to[i] = y;
if (from[i] > to[i]) {
swap(from[i], to[i]);
}
}
auto get_another = [&](int x) {
return x >= n ? x - n : x + n;
};
vector<vector<int>> adj(n << 1);
for (int i = 0; i < m; ++i) {
adj[get_another(from[i])].push_back(to[i]);
adj[get_another(to[i])].push_back(from[i]);
}
vector<int> dfn(n << 1, -1), low(n << 1, -1), scc(n << 1, -1);
stack<int> st;
int cc = 0, tt = 0;
function<void(int)> tarjan = [&](int x) {
dfn[x] = low[x] = tt++;
st.push(x);
for (auto y : adj[x]) {
if (!~dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
} else if (!~scc[y]) {
low[x] = min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
for (int t = -1; t != x; ) {
t = st.top();
scc[t] = cc;
st.pop();
}
++cc;
}
};
for (int i = 0; i < n << 1; ++i) {
if (!~dfn[i]) {
tarjan(i);
}
}
for (int i = 0; i < n; ++i) {
if (scc[i] == scc[i + n]) {
return false;
}
}
vector<bool> ban_scc(cc);
for (int i = 0; i < n; ++i) {
if (s[i] == 'E') {
ban_scc[scc[i]] = ban_scc[scc[i + n]] = true;
} else {
if (ban_scc[scc[i]] || ban_scc[scc[i + n]]) {
return false;
}
}
}
for (int i = 0; i < cc; ++i) {
ban_scc[i] = false;
}
for (int i = 0; i < n; ++i) {
if (s[i] == 'A') {
if (ban_scc[scc[i]]) {
return false;
}
ban_scc[scc[i]] = true;
if (ban_scc[scc[i + n]]) {
return false;
}
ban_scc[scc[i + n]] = true;
}
}
vector<bool> can(cc);
vector<vector<int>> graph(cc);
for (int x = 0; x < n << 1; ++x) {
for (auto y : adj[x]) {
if (scc[x] != scc[y]) {
graph[scc[x]].push_back(scc[y]);
}
}
}
for (int x = 0; x < cc; ++x) {
for (auto y : graph[x]) {
if (can[y] || ban_scc[y]) {
can[x] = true;
}
}
if (can[x] && ban_scc[x]) {
return false;
}
}
return true;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
puts(solve() ? "TRUE" : "FALSE");
}
return 0;
}
Interval-Free Permutations
考虑用总的方案数减去不合法的方案数,对于不合法的方案,用最少的极长连续段覆盖序列(每个序列至少覆盖一次),如果两个连续段有交,那么它们一定可以合并成一个连续的大段,所以最后有两种情况:
- 划分段数为 2 2 2 ,那么一定是一个前缀或者一个后缀是 1 , 2 , ⋯   , k 1, 2, \cdots, k 1,2,⋯,k 。
- 划分段数大于 2 2 2 ,每个位置恰好被覆盖一次。
然后用DP算方案数即可。
你也可以选择OEIS+打表
#include <bits/stdc++.h>
using namespace std;
const int N = 400;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt, md;
scanf("%d %d", &tt, &md);
auto add = [&](int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
};
auto sub = [&](int &x, int y) {
x -= y;
if (x < 0) {
x += md;
}
};
auto mul = [&](int x, int y) {
return (long long)x * y % md;
};
vector<int> fact(N + 1);
fact[0] = 1;
for (int i = 0; i < N; ++i) {
fact[i + 1] = mul(fact[i], i + 1);
}
vector<int> ways(N + 1);
for (int i = 1; i <= N; ++i) {
ways[i] = fact[i];
for (int j = 1; j < i; ++j) {
sub(ways[i], mul(ways[j], fact[i - j]));
}
}
vector<vector<int>> dp(N + 1, vector<int> (N + 1));
dp[0][0] = 1;
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= i; ++j) {
for (int k = 1; k <= i; ++k) {
add(dp[i][j], mul(dp[i - k][j - 1], fact[k]));
}
}
}
vector<int> f(N + 1);
for (int i = 1; i <= N; ++i) {
f[i] = fact[i];
for (int j = 1; j < i; ++j) {
sub(f[i], mul(2, mul(ways[j], fact[i - j])));
}
for (int j = 3; j < i; ++j) {
sub(f[i], mul(dp[i][j], f[j]));
}
}
f[2] = 2;
while (tt--) {
int n;
scanf("%d", &n);
printf("%d\n", f[n]);
}
return 0;
}
JS Minification
模拟,最后加空格的时候贪心即可。
#include <bits/stdc++.h>
using namespace std;
const int MAX = 20;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
{
string foo;
getline(cin, foo);
stringstream ss;
ss << foo;
ss >> n;
}
set<string> reserved;
{
string foo;
getline(cin, foo);
stringstream ss;
ss << foo;
for (int i = 0; i < n; ++i) {
string bar;
ss >> bar;
reserved.insert(bar);
}
}
int m;
{
string foo;
getline(cin, foo);
stringstream ss;
ss << foo;
ss >> m;
}
vector<string> tokens;
auto parse_reserved = [&](string s, int start) {
int result = 0;
string current;
for (int i = start; i < start + MAX && i < s.length() && s[i] != '#'; ++i) {
current += s[i];
if (reserved.find(current) != reserved.end()) {
result = i - start + 1;
}
}
return result;
};
auto parse_number = [&](string s, int start) {
int result = 0;
while (start + result < s.length() && isdigit(s[start + result])) {
++result;
}
return result;
};
auto parse_word = [&](string s, int start) {
if (isdigit(s[start])) {
return 0;
}
int result = 0;
auto is_valid = [&](char c) {
return isdigit(c) || isalpha(c) || c == '_' || c == '$';
};
while (start + result < s.length() && is_valid(s[start + result])) {
++result;
}
return result;
};
auto parse = [&](string s, int start) {
return max(max(parse_reserved(s, start), parse_number(s, start)), parse_word(s, start));
};
while (m--) {
string foo;
getline(cin, foo);
for (int i = 0; i < foo.length(); ++i) {
if (foo[i] == ' ') {
continue;
}
if (foo[i] == '#') {
break;
}
int length = parse(foo, i);
tokens.push_back(foo.substr(i, length));
i += length - 1;
}
}
map<string, string> changed;
string last = "";
auto find_next = [&]() {
do {
int i = last.length() - 1;
while (~i && last[i] == 'z') {
--i;
}
if (~i) {
++last[i++];
while (i < last.length()) {
last[i++] = 'a';
}
} else {
last = string(last.length() + 1, 'a');
}
} while (reserved.find(last) != reserved.end());
};
for (auto &s : tokens) {
if (reserved.find(s) == reserved.end() && !isdigit(s[0])) {
if (changed.find(s) == changed.end()) {
find_next();
changed[s] = last;
}
s = changed[s];
}
}
int p = tokens.size();
for (int i = 0; i < tokens.size(); ++i) {
string foo = tokens[i];
for (int j = i + 1; j < tokens.size(); ++j) {
foo += tokens[j];
if (parse(foo, 0) != tokens[i].length()) {
p = min(p, j - 1);
break;
}
if (foo.length() > MAX) {
break;
}
}
cout << tokens[i];
if (i == p) {
cout << " ";
p = tokens.size();
}
}
cout << endl;
return 0;
}
King Kog’s Reception
就是求 max t j + ∑ t j ≤ t i ≤ t d i \max t_j + \sum_{t_j\le t_i\le t} d_i maxtj+∑tj≤ti≤tdi ,线段树维护即可。
#include <bits/stdc++.h>
using namespace std;
class segtree_t {
public:
struct node_t {
long long tag = 0, value = 0;
void apply(int l, int r, long long v) {
tag += v;
value += v;
}
};
vector<node_t> tree;
int n;
node_t unite(const node_t &l, const node_t &r) {
node_t result;
result.value = min(l.value, r.value);
return result;
}
segtree_t(int n):n(n) {
tree.resize((n << 1) - 1);
}
inline void pull(int x, int z) {
tree[x] = unite(tree[x + 1], tree[z]);
}
inline void push(int x, int l, int r) {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
if (tree[x].tag) {
tree[x + 1].apply(l, y, tree[x].tag);
tree[z].apply(y + 1, r, tree[x].tag);
tree[x].tag = 0;
}
}
void build(int x, int l, int r) {
if (l != r) {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
build(x + 1, l, y);
build(z, y + 1, r);
pull(x, z);
} else {
tree[x].value = -l;
}
}
template<typename T> void build(int x, int l, int r, const vector<T> &v) {
if (l == r) {
tree[x].apply(l, r, v[l]);
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
build(x + 1, l, y, v);
build(z, y + 1, r, v);
pull(x, z);
}
}
template<typename T> void build(const vector<T> &v) {
build(0, 0, n - 1, v);
}
template<typename... T> void modify(int x, int l, int r, int ql, int qr, const T&... v) {
if (l == ql && r == qr) {
tree[x].apply(l, r, v...);
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
push(x, l, r);
if (qr <= y) {
modify(x + 1, l, y, ql, qr, v...);
} else if (ql > y) {
modify(z, y + 1, r, ql, qr, v...);
} else {
modify(x + 1, l, y, ql, y, v...);
modify(z, y + 1, r, y + 1, qr, v...);
}
pull(x, z);
}
}
template<typename... T> void modify(int l, int r, const T&... v) {
modify(0, 0, n - 1, l, r, v...);
}
node_t query(int x, int l, int r, int ql, int qr) {
if (l == ql && r == qr) {
return tree[x];
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
push(x, l, r);
if (qr <= y) {
return query(x + 1, l, y, ql, qr);
} else if (ql > y) {
return query(z, y + 1, r, ql, qr);
} else {
return unite(query(x + 1, l, y, ql, y), query(z, y + 1, r, y + 1, qr));
}
}
}
node_t query(int l, int r) {
return query(0, 0, n - 1, l, r);
}
};
const int MAX = 1000000;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
segtree_t segtree(MAX + 1);
segtree.build(0, 0, MAX);
int tt;
cin >> tt;
vector<pair<int, int>> a(tt);
for (int qq = 0; qq < tt; ++qq) {
string type;
cin >> type;
if (type == "+") {
int t, d;
cin >> t >> d;
a[qq] = make_pair(t, d);
segtree.modify(t, MAX, d);
} else if (type == "-") {
int i;
cin >> i;
--i;
int t = a[i].first, d = a[i].second;
segtree.modify(t, MAX, -d);
} else {
int t;
cin >> t;
printf("%lld\n", segtree.query(t, t).value - segtree.query(0, t - 1).value + 1);
}
}
return 0;
}
Lazyland
贪心。
#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<pair<int, int>> a(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i].first);
}
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i].second);
}
sort(a.begin(), a.end());
int need = m;
vector<int> choice;
for (int i = 0, j = 0; i < n; i = j) {
while (j < n && a[j].first == a[i].first) {
++j;
}
for (int k = i; k + 1 < j; ++k) {
choice.push_back(a[k].second);
}
--need;
}
sort(choice.begin(), choice.end());
long long answer = 0;
for (int i = 0; i < need; ++i) {
answer += choice[i];
}
printf("%lld\n", answer);
return 0;
}
Minegraphed
具体构造见代码。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
cin >> n;
vector<vector<string>> board(3, vector<string> (n * 3, string(n * 3, '#')));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n * 3; ++j) {
board[0][i * 3][j] = board[2][j][i * 3] = '.';
}
board[1][i * 3][i * 3 + 1] = board[1][i * 3 + 1][i * 3 + 1] = board[2][i * 3 + 1][i * 3 + 1] = '.';
for (int j = 0; j < n; ++j) {
int can;
cin >> can;
if (can) {
for (int k = 0; k < 3; ++k) {
board[k][j * 3 + 1][i * 3 + 1] = '.';
}
}
}
board[0][i * 3][n * 3 - 1] = i + '1';
}
cout << n * 3 << " " << n * 3 << " " << 3 << endl;
for (int i = 2; ~i; --i) {
for (int j = 0; j < n * 3; ++j) {
cout << board[i][j] << endl;
}
if (i) {
cout << endl;
}
}
return 0;
}