L1-1 宇宙无敌大招呼
签到
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
string s;
cin >> s;
s = "Hello " + s;
cout << s << "\n";
return 0;
}
L1-2 寻找250
签到
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int x, idx = 0;
while(cin >> x) {
idx ++;
if(x == 250) {
cout << idx << "\n";
break;
}
}
return 0;
}
L1-3 装睡
签到
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n;
cin >> n;
while(n -- ) {
string s;
int x, y;
cin >> s >> x >> y;
if(x < 15 or x > 20 or y < 50 or y > 70)
cout << s << "\n";
}
return 0;
}
L1-4 生命游戏
按要求模拟
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
const int dx[] = {0, 0, 1, -1, 1, 1, -1, -1};
const int dy[] = {-1, 1, 0, 0, -1, 1, -1, 1};
char g[55][55], ng[55][55];
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int T;
cin >> T;
while(T -- ) {
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; ++ i) cin >> (g[i] + 1);
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= m; ++ j) {
int cnt = 0;
for(int k = 0; k < 8; ++ k) {
int xx = i + dx[k], yy = j + dy[k];
if(xx >= 1 and yy >= 1 and xx <= n and yy <= m and g[xx][yy] == '1')
cnt ++;
}
if(g[i][j] == '1') {
if(cnt <= 1 or cnt >= 4) ng[i][j] = '0';
else ng[i][j] = '1';
}
else {
if(cnt == 3) ng[i][j] = '1';
else ng[i][j] = '0';
}
}
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j <= m; ++ j)
cout << ng[i][j];
cout << "\n";
}
}
return 0;
}
L1-5 个位数统计
按要求模拟
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
string s;
cin >> s;
map<int, int> mp;
for(int i = 0; i < s.size(); ++ i)
mp[s[i] - '0'] ++;
for(auto [x, y] : mp)
cout << x << ":" << y << "\n";
return 0;
}
L1-6 整除分块
考虑\(\left\lfloor\dfrac{n}{i}\right\rfloor\) \((i = 1, 2, ..., n)\) , 该式最多只有 $2 \sqrt n $ 个取值
- 当 \(i \le \sqrt n\), 最多只有 \(\sqrt n\) 个不同的取值
- 当 \(i > \sqrt n\), 式子取值从 \(\sqrt n\) 到 \(1\), 最多只有 \(\sqrt n\) 个不同值
故该式最多只有 \(2\sqrt n\) 个取值根据 \(x\) 求最大 \(t\), 使得 \(\left\lfloor\dfrac{n}{x}\right\rfloor = \left\lfloor\dfrac{n}{t}\right\rfloor\) 且 \(\left\lfloor\dfrac{n}{x}\right\rfloor > \left\lfloor\dfrac{n}{t + 1}\right\rfloor\), \(t = \left\lfloor\dfrac{n}{\left\lfloor\dfrac{n}{x}\right\rfloor}\right\rfloor\)
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int T;
cin >> T;
while(T -- ) {
int n, x;
cin >> n >> x;
vector<int> v;
for(int l = 1, r = 0; l <= n; l = r + 1) {
r = min(n, n / (n / l));
v.push_back(n / l);
}
sort(v.begin(), v.end());
cout << lower_bound(v.begin(), v.end(), x) - v.begin() + 1 << "\n";
}
return 0;
}
L1-7 点赞
按要求模拟
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n;
cin >> n;
map<int, int> mp;
for(int i = 1, k; i <= n; ++ i) {
cin >> k;
for(int j = 0, x; j < k; ++ j) {
cin >> x;
mp[x] ++;
}
}
int id = 0;
for(auto [x, y] : mp) {
if(y >= mp[id]) id = x;
}
cout << id << " " << mp[id] << "\n";
return 0;
}
L1-8 古风排版
先用空格将字符串长度补全至 \(n\) 的整数倍,然后按要求模拟即可
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n;
cin >> n;
string s;
getline(cin, s);
getline(cin, s);
int m = (s.size() + n - 1) / n * n;
while(s.size() < m) s += " ";
for(int i = n - 1; i >= 0; -- i) {
for(int j = s.size() - 1 - i; j >= 0; j -= n)
cout << s[j];
cout << "\n";
}
return 0;
}
L2-1 奥运排行榜
按照四种关键字排序模拟
坑点:若四个国家金牌数为 \(4\) \(3\) \(3\) \(2\),排名应该是 \(1\) \(2\) \(2\) \(4\),而不是 \(1\) \(2\) \(2\) \(3\)
Sample Code (C++)
#include <bits/stdc++.h>
using namespace std;
struct Node {
int a, b, c, id;
};
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, m;
cin >> n >> m;
vector<Node> v(n);
for(int i = 0; i < n; ++ i) {
cin >> v[i].a >> v[i].b >> v[i].c;
v[i].id = i;
}
vector<vector<int>> rk(n, vector<int>(4));
sort(v.begin(), v.end(), [&](Node x, Node y){
return x.a > y.a;
});
int idx = 1;
for(int i = 0; i < n; ++ i) {
if(i and v[i].a != v[i - 1].a) idx = i + 1;
rk[v[i].id][0] = idx;
}
sort(v.begin(), v.end(), [&](Node x, Node y){
return x.b > y.b;
});
idx = 1;
for(int i = 0; i < n; ++ i) {
if(i and v[i].b != v[i - 1].b) idx = i + 1;
rk[v[i].id][1] = idx;
}
sort(v.begin(), v.end(), [&](Node x, Node y){
return x.a * y.c > y.a * x.c;
});
idx = 1;
for(int i = 0; i < n; ++ i) {
if(i and v[i].a * v[i - 1].c != v[i - 1].a * v[i].c) idx = i + 1;
rk[v[i].id][2] = idx;
}
sort(v.begin(), v.end(), [&](Node x, Node y){
return x.b * y.c > y.b * x.c;
});
idx = 1;
for(int i = 0; i < n; ++ i) {
if(i and v[i].b * v[i - 1].c != v[i - 1].b * v[i].c) idx = i + 1;
rk[v[i].id][3] = idx;
}
for(int i = 1; i <= m; ++ i) {
int x, t = 0;
cin >> x;
for(int j = 0; j < 4; ++ j) {
if(rk[x][j] < rk[x][t])
t = j;
}
cout << rk[x][t] << ':' << t + 1 << " \n"[i == m];
}
return 0;
}
L2-2 文件传输
并查集模板题
Sample Code (C++)
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n;
cin >> n;
vector<int> f(n);
for(int i = 0; i < n; ++ i) f[i] = i;
function<int(int)> getf = [&](int x) {
return x == f[x] ? f[x] : f[x] = getf(f[x]);
};
char op;
while(cin >> op) {
if(op == 'S') {
int cnt = 0;
for(int i = 0; i < n; ++ i) cnt += f[i] == i;
if(cnt == 1) cout << "The network is connected.\n";
else cout << "There are "<< cnt << " components.\n";
break;
}
int x, y;
cin >> x >> y;
x --, y --;
int fx = getf(x), fy = getf(y);
if(op == 'I') {
if(fx != fy)
f[fx] = fy;
}
else {
if(fx == fy) cout << "yes\n";
else cout << "no\n";
}
}
return 0;
}
L2-3 功夫传人
遍历树,统计答案
Sample Code (C++)
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int n;
double ans, z, r;
vector<int> g[100010], b;
void dfs(int u, double val) {
if(b[u]) ans += val * b[u];
else {
for(auto v : g[u]) dfs(v, val * (100.0 - r) / 100.0);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> z >> r;
b.resize(n);
for(int i = 0, k; i < n; ++ i) {
cin >> k;
if(not k) cin >> b[i];
for(int j = 0, x; j < k; ++ j) {
cin >> x;
g[i].push_back(x);
}
}
dfs(0, z);
cout << (LL)ans << "\n";
return 0;
}
L2-4 玩转二叉树
根据中序遍历和前序遍历建树,按要求层序遍历即可
Sample Code (C++)
#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
int n, in[N], pre[N], lc[N], rc[N];
int solve(int lin, int rin, int lpre, int rpre) {
if(lin > rin) return 0;
int rt = pre[lpre];
int p = lin;
while(in[p] != rt) p ++;
lc[rt] = solve(lin, p - 1, lpre + 1, lpre + p - lin);
rc[rt] = solve(p + 1, rin, lpre + p - lin + 1, rpre);
return rt;
}
vector<int> p[32];
void dfs(int u, int dep) {
p[dep].push_back(u);
if(lc[u]) dfs(lc[u], dep + 1);
if(rc[u]) dfs(rc[u], dep + 1);
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> n;
for(int i = 0; i < n; ++ i) cin >> in[i];
for(int i = 0; i < n; ++ i) cin >> pre[i];
solve(0, n - 1, 0, n - 1);
dfs(pre[0], 0);
int cnt = 0;
for(int i = 0; i < 30; ++ i) {
reverse(p[i].begin(), p[i].end());
for(int j = 0; j < p[i].size(); ++ j) {
cnt ++;
cout << p[i][j] << " \n"[cnt == n];
}
}
return 0;
}
L3-1 森森旅游
先预处理从 \(1\) 和 \(n\) 出发的花费,即在原图 \(G\) 上从起点 \(1\) 以现金为边权跑一遍 \(dijkstra\), 将原图的边反向建图得到 \(rG\), 在 \(rG\) 上从终点 \(n\) 以旅游金为边权跑一遍 \(dijkstra\), 然后用一个 \(multiset\) 维护在 \(n\) 个城市兑换旅游金的现金花费,可以支持动态修改,且可以取最小值
Sample Code (C++)
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
using PII = pair<int, int>;
using LL = long long;
using PLI = pair<LL, int>;
const LL INF = 1e18;
vector<PII> G[N], rG[N];
int n, m, q, a[N];
LL dis[N], rdis[N], res[N];
bool st[N];
void dijkstra(int S, LL dis[], int op) {
for(int i = 1; i <= n; ++ i) {
dis[i] = INF;
st[i] = false;
}
priority_queue<PLI, vector<PLI>, greater<PLI>> Q;
Q.push({0, S});
dis[S] = 0;
while(!Q.empty()) {
int u = Q.top().second;
Q.pop();
if(st[u]) continue;
st[u] = true;
if(op) {
for(auto &[v, w] : G[u])
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
Q.push({dis[v], v});
}
}
else {
for(auto &[v, w] : rG[u]) {
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
Q.push({dis[v], v});
}
}
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m >> q;
for(int i = 0; i < m; ++ i) {
int u, v, c, d;
cin >> u >> v >> c >> d;
G[u].push_back({v, c});
rG[v].push_back({u, d});
}
for(int i = 1; i <= n; ++ i) cin >> a[i];
dijkstra(1, dis, 1);
dijkstra(n, rdis, 0);
multiset<LL> S;
for(int i = 1; i <= n; ++ i) {
if(dis[i] == INF or rdis[i] == INF) continue;
res[i] = dis[i] + (rdis[i] + a[i] - 1) / a[i];
S.insert(res[i]);
}
while(q -- ) {
int x, v;
cin >> x >> v;
if(dis[x] != INF and rdis[x] != INF) {
auto it = S.find(res[x]);
S.erase(it);
res[x] = dis[x] + (rdis[x] + v - 1) / v;
S.insert(res[x]);
}
cout << *S.begin() << "\n";
}
return 0;
}
L3-2 至多删三个字符
设 \(dp[i][j]\) 为前 \(i\) 个字符删除了 \(j\) 个,得到不同字符串的个数
首先考虑一个简单问题,不考虑删除字符后得到字符串的重复
那么有状态转移方程: \(dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]\)
现在考虑如何去重,例如串 \(******a**a***\),设第一个 'a' 的位置为 \(k\), 第二个 'a' 的位置为 \(i\)
当我们删除从 \(k\) 开始的 \(a**\) 和 删除到 \(i\) 结束的 \(**a\) 时,得到的字符串相同,需要去重的情况是第一个 'a' 字符前面(即 \(k - 1\)) 去除 \(i - 3\) 个字符的情况,即为 \(dp[k - 1][j - (i - k)]\),故当出现相同字符时按照上述去重方式去重即可
Sample Code (C++)
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1000010;
LL dp[N][4];
char s[N];
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> (s + 1);
int n = strlen(s + 1);
dp[0][0] = 1;
for(int i = 1; i <= n; ++ i)
for(int j = 0; j <= 3; ++ j) {
if(i < j) continue;
dp[i][j] = dp[i - 1][j];
if(j >= 1) dp[i][j] += dp[i - 1][j - 1];
for(int k = i - 1; k >= 1 && i - k <= j; -- k)
if(s[i] == s[k]) {
dp[i][j] -= dp[k - 1][j - (i - k)];
break;
}
}
LL res = 0;
for(int i = 0; i <= 3; ++ i) res += dp[n][i];
cout << res << "\n";
return 0;
}
L3-3 胜利者集合
首先枚举每一个玩家 \(x\) 是否可以成为胜利者,当对一个玩家进行判断时,他的胜场应尽可能多,那么他还未进行的比赛将全部获胜。
此时假设他的胜场为 \(win\), 于是问题转化为当其他人的胜场最大为 \(win - 1\) 的情况下,是否可以构造出一种合法方案?
对于上述问题,可以转化为一个最大流的问题,考虑如何建图:
- 建立两组点,第一组点是比赛(除去与 \(x\) 进行的比赛),第二组点是玩家(除去 \(x\)),流量即为胜利
- 从源点 \(S\) 向所有比赛连接一条容量为 \(1\) 的边
- 若当前比赛未比,则从当前比赛到两个玩家各连一条容量为 \(1\) 的边
- 若当前比赛已比,则从当前比赛到胜者连一条容量为 \(1\) 的边
- 若某玩家胜过 \(x\),则从当前玩家向汇点 \(T\) 连一条容量为 \(win - 2\) 的边
- 若某玩家输给 \(x\),则从当前玩家向汇点 \(T\) 连一条容量为 \(win - 1\) 的边
判断最大流是否满流,若满流,则存在一种合法方案,即该玩家 \(x\) 可以成为胜利者
Sample Code (C++)
#include <bits/stdc++.h>
using namespace std;
const int N = 1500, M = 10010, INF = 1e9;
int n, m, S, T;
struct Edge {
int to, nxt, flow;
}line[M];
int fist[N], idx, d[N], cur[N];
void add(int x, int y, int z) {
line[idx] = {y, fist[x], z}; fist[x] = idx ++;
line[idx] = {x, fist[y], 0}; fist[y] = idx ++;
}
bool bfs() {
queue<int> q;
memset(d, -1, sizeof d);
q.push(S), d[S] = 0, cur[S] = fist[S];
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = fist[u]; i != -1; i = line[i].nxt) {
int v = line[i].to;
if(d[v] == -1 && line[i].flow) {
d[v] = d[u] + 1;
cur[v] = fist[v];
if(v == T) return 1;
q.push(v);
}
}
}
return 0;
}
int find(int u, int limit) {
if(u == T) return limit;
int flow = 0;
for(int i = cur[u]; i != -1 && flow < limit; i = line[i].nxt) {
cur[u] = i;
int v = line[i].to;
if(d[v] == d[u] + 1 && line[i].flow) {
int t = find(v, min(line[i].flow, limit - flow));
if(!t) d[v] = -1;
line[i].flow -= t;
line[i ^ 1].flow += t;
flow += t;
}
}
return flow;
}
int dinic() {
int res = 0, flow;
while(bfs()) while(flow = find(S, INF)) res += flow;
return res;
}
int main() {
ios::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m;
vector<vector<int>> g(n, vector<int>(n, 0));
for(int i = 0; i < m; ++ i) {
int u, v;
cin >> u >> v;
u --, v --;
g[u][v] = 1, g[v][u] = -1;
}
S = n + (n - 2) * (n - 1) / 2;
T = S + 1;
int flag = 0;
for(int i = 0; i < n; ++ i) {
int win = n - 1;
for(int j = 0; j < n; ++ j)
if(g[i][j] == -1) win --;
idx = 0;
memset(fist, -1, sizeof fist);
int cur = n;
for(int j = 0; j < n; ++ j) {
if(j == i) continue;
for(int k = j + 1; k < n; ++ k) {
if(k == i) continue;
add(S, cur, 1);
if(g[j][k] == 0) {
add(cur, j, 1);
add(cur, k, 1);
}
if(g[j][k] == 1)
add(cur, j, 1);
if(g[j][k] == -1)
add(cur, k, 1);
cur ++;
}
}
bool ok = true;
for(int j = 0; j < n; ++ j) {
if(win - 1 - (g[j][i] > 0) < 0) {
ok = false;
break;
}
if(j != i)
add(j, T, win - 1 - (g[j][i] > 0));
}
if(!ok) continue;
if(dinic() == (n - 1) * (n - 2) / 2) {
if(flag) cout << ' ';
cout << i + 1;
flag = 1;
}
}
cout << '\n';
return 0;
}