A. 罚时#
签到
略
B. 数学题#
思维,签到
输出n个9即可
ac code#
1
2
3
4
5
6
7
| #include<iostream>
int main()
{
int n; std::cin >> n;
for(int i = 1; i <= n; i ++) std::cout << 9;
return 0;
}
|
C. 干杯!#
字符串,签到
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #include<iostream>
#include<cstdlib>
#include<cstring>
#include<set>
using namespace std;
string s;
void solve()
{
getline(cin, s);
set<char> st;
for(auto ch : s)
if(isalpha(ch)) st.insert(ch);
cout << st.size();
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
D. 向左看#
单调栈
维护一个单调递减的栈,栈顶即左边第一个小于的数。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| #include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 1e5 + 10;
int n;
void solve()
{
cin >> n;
stack<int> st;
for(int i = 1, h; i <= n; i ++){
cin >> h;
while(st.size() && st.top() >= h) st.pop();
if(st.empty()) cout << -1 << ' ';
else cout << st.top() << ' ';
st.push(h);
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
E. HRBUST#
字符串,签到
ac code#
1
2
3
4
5
6
7
8
9
10
| string s;
void solve()
{
cin >> s;
int ans = 0;
for(int i = 0; i + 5 < s.size(); i ++)
if(s[i] == 'H' && s[i + 1] == 'R' && s[i + 2] == 'B' && s[i + 3] == 'U' && s[i + 4] == 'S' && s[i + 5] == 'T')
ans ++;
cout << ans;
}
|
F. 时间管理#
暴力
发现n<=20,枚举每一种分配方法复杂度为o($2^n$)。
枚举分配方法可以用二进制位掩码。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| #include<iostream>
using namespace std;
using LL = long long;
int n, k[25];
void solve()
{
cin >> n;
for(int i = 0; i < n; i ++) cin >> k[i];
LL a, b, ans = 1e18;
for(LL state = 0; state < 1LL << n; state ++){
a = 0, b = 0;
for(int i = 0; i < n; i ++)
if(state >> i & 1) a += k[i];
else b += k[i];
ans = min(ans, max(a, b));
}
cout << ans;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
solve();
return 0;
}
|
G. 墨墨的妙妙卡片#
思维,签到
只要有一个卡片的初始位置正确就能一次完成排序。
ac code#
1
2
3
4
5
6
| string s;
void solve()
{
cin >> s;
cout << (s[0] == 'a' || s[1] == 'b' || s[2] == 'c' ? "YES" : "NO") << '\n';
}
|
H. 墨墨与春日影#
思维,签到
可以把演奏2分钟视为演奏2次1分钟,3分钟视为演奏3次1分钟。看是否能把所有演出平均分配到两次即可。
ac code#
1
2
3
4
5
6
| int a, b, c;
void solve()
{
cin >> a >> b >> c;
cout << (a + b * 2 + c * 3 & 1) << '\n';
}
|
I. 复制粘贴吧的暴力排序#
排序
排序后去重,可以使用unique函数等。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 1e7 + 10;
int n;
vector<int> a;
void solve()
{
cin >> n;
for(int i = 0, x; i < n; i ++) cin >> x, a.push_back(x);
sort(a.begin(), a.end(), greater<int>());
a.erase(unique(a.begin(), a.end()), a.end());
for(auto x : a) cout << x << ' ';
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
J. 救赎之道,不在其中#
数学,快速幂
所有可能的情况一共$m^n$种,每一个犯人可信仰有m种情况,无法越狱的情况为两两相邻
$$(m - 1)^{n-1}$$
所以会发生越狱的情况即为
$$m^n - (m - 1)^{n-1} * m$$
数字较大,需要使用模下快速幂。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int MOD = 100003;
LL qpow(LL a, LL n)
{
LL ret = 1;
while(n){
if(n & 1) ret = ret * a % MOD;
a = a * a % MOD;
n >>= 1;
}
return ret;
}
LL n, m;
void solve()
{
cin >> m >> n;
LL ans = (qpow(m, n) - qpow(m - 1, n - 1) * m % MOD + MOD) % MOD;
cout << ans;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
K. 我们来玩游戏吧!#
数据结构
需要维护一种数据结构,支持:区间修改,区间查询。
可以选择树状数组,线段树等,复杂度o(mlogn)。
(这道题数据出弱了,使得暴力也能ac。。。)
11/8更新:感谢勘误,修改了会爆int的问题,现在能ac了
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 1e5 + 10;
int n, m;
LL s1[N], s2[N];
void add(int x, int k)
{
for(int i = x; i <= n; i += lowbit(i)) s1[i] += k, s2[i] += 1LL * x * k;
}
LL query(int x)
{
LL ret = 0;
for(int i = x; i; i -= lowbit(i)) ret += (LL)(x + 1) * s1[i] - s2[i];
return ret;
}
void solve()
{
cin >> n >> m;
for(int i = 1, x; i <= n; i ++) cin >> x, add(i, x), add(i + 1, -x);
while(m --){
int op, l, r, k;
cin >> op >> l >> r;
if(op == 1) cin >> k, add(l, k), add(r + 1, -k);
else cout << query(r) - query(l - 1) << '\n';
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
L. 再见啦!#
线性dp
dp经典题。
先考虑一个人的情况,因为每次只能向右或向下,转移dp(i, j) = max(dp(i - 1, j), dp(i, j - 1))
因为答案要在全局最优,所以不能分成两次去走。我们考虑两人一起走,dp(x1, y1, x2, y2),可以优化状态数:
因为只能向右或向下,每次移动后x1 + y1 = x2 + y2 = k <= 2 * n
于是有dp(k, x1, x2),y1 = k - x1, y2 = k - x2
两人将组合出4种转移。
复杂度o($n^3$)
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
int n, g[30][30], dp[30][30][30];
void solve()
{
cin >> n;
int x, y, w;
while(cin >> x >> y >> w, ~x && ~y && ~w) g[x][y] = w;
for(int k = 2; k <= n << 1; k ++)
for(int x1 = 1; x1 <= n; x1 ++)
for(int x2 = 1; x2 <= n; x2 ++){
int y1 = k - x1, y2 = k - x2;
if(y1 < 1 || y1 > n || y2 < 1 || y2 > n) continue;
int &t = dp[k][x1][x2];
int v = g[x1][y1] + (x1 == x2 ? 0 : g[x2][y2]);
t = max(t, max({dp[k - 1][x1 - 1][x2],
dp[k - 1][x1][x2 - 1],
dp[k - 1][x1 - 1][x2 - 1],
dp[k - 1][x1][x2]}) + v);
}
cout << dp[n << 1][n][n];
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
M. 墨墨想要去玩#
排序,枚举
分别对a,b,c数组排序,枚举前三大的所有组合,两两间的日期不能相同。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 1e6 + 10;
int n;
PII t[3][N];
void solve()
{
cin >> n;
for(int i = 0; i < 3; i ++){
for(int j = 1; j <= n; j ++) cin >> t[i][j].fi, t[i][j].se = j;
sort(t[i] + 1, t[i] + n + 1, greater<PII>());
}
int ans = 0;
for(int i = 1; i <= 3; i ++)
for(int j = 1; j <= 3; j ++)
for(int k = 1; k <= 3; k ++){
auto [a, at] = t[0][i];
auto [b, bt] = t[1][j];
auto [c, ct] = t[2][k];
if(at == bt || bt == ct || at == ct) continue;
ans = max(ans, a + b + c);
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
cin >> Case;
while(Case --) solve();
return 0;
}
|
N. 走格子#
bfs
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| #include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
int n, m, g[110][110], vis[110][110];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
struct node
{
int x, y, dis;
};
void solve()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) cin >> g[i][j];
if(g[1][1] == 3){
cout << 0;
return ;
}
queue<node> q;
q.push({1, 1, 0});
vis[1][1] = 1;
while(q.size()){
auto [x, y, dis] = q.front();
q.pop();
vis[x][y] = 1;
for(int i = 0, xx, yy; i < 4; i ++){
xx = dx[i] + x, yy = dy[i] + y;
if(xx < 1 || xx > n || yy < 1 || yy > m) continue;
if(g[xx][yy] == 2 || vis[xx][yy]) continue;
if(g[xx][yy] == 3){
cout << "Yes " << dis + 1;
return ;
}
q.push({xx, yy, dis + 1});
vis[xx][yy] = 1;
}
}
cout << "No";
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
O. 组建乐队#
枚举,贪心
考虑枚举直接枚举每种价格的个数,复杂度过高。
贪心地想,当我们拿3个1¥时,更好的方案是拿1个3¥代替,这对于3¥,6¥,10¥来说是一样的。每层循环不会超过2。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| #include<iostream>
using namespace std;
using LL = long long;
void solve()
{
int n; cin >> n;
int ans = 2e9;
for(int i1 = 0; i1 <= 2; i1 ++)
for(int i3 = 0; i3 <= 1; i3 ++)
for(int i6 = 0; i6 <= 2; i6 ++)
for(int i10 = 0; i10 <= 2; i10 ++){
int x = i1 + i3 * 3 + i6 * 6 + i10 * 10;
int t = i1 + i3 + i6 + i10 + (n - x) / 15;
if(x <= n && !((n - x) % 15))
ans = min(ans, t);
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case; cin >> Case;
while(Case --) solve();
return 0;
}
|
P. 进击的败犬#
二分
二分经典题进击的奶牛。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 1e5 + 10;
int n, c, a[N];
bool check(int x)
{
int cnt = 1;
for(int i = 1, last = a[1]; i <= n; i ++)
if(a[i] - last >= x) cnt ++, last = a[i];
return cnt >= c;
}
void solve()
{
cin >> n >> c;
for(int i = 1; i <= n; i ++) cin >> a[i];
sort(a + 1, a + n + 1);
int l = 1, r = 1e9 + 10;
while(l < r){
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
Q. 妮蔻的MAJOR梦#
dfs
如果在非初始地图中,访问到在初始地图访问过的点,即为开放图。
可以维护vis(x, y, 0) : 初始地图是否访问过,vis(x, y, 1)/vis(x, y, 2) : 非初始地图的对应x/y坐标。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| #include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
int n, m, vis[1510][1510][3];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
string g[1510];
bool ok;
void dfs(int x, int y, int lx, int ly)
{
if(ok) return ;
if(vis[x][y][0] && (vis[x][y][1] != lx || vis[x][y][2] != ly)){
ok = 1;
return ;
}
vis[x][y][1] = lx, vis[x][y][2] = ly, vis[x][y][0] = 1;
for(int i = 0; i < 4; i ++) {
int xx = (x + dx[i] + n) % n, yy = (y + dy[i] + m) % m;
int lxx = lx + dx[i], lyy = ly + dy[i];
if(g[xx][yy] == '#') continue;
if(vis[xx][yy][1] != lxx || vis[xx][yy][2] != lyy || !vis[xx][yy][0])
dfs(xx, yy, lxx, lyy);
}
}
void solve()
{
memset(vis, 0, sizeof vis);
ok = 0;
PII S;
for(int i = 0; i < n; i ++){
cin >> g[i];
for(int j = 0; j < m; j ++)
if(g[i][j] == 'S') S = {i, j};
}
dfs(S.fi, S.se, S.fi, S.se);
cout << (ok ? "Yes" : "No") << '\n';
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(cin >> n >> m) solve();
return 0;
}
|
R. 不给糖就捣蛋#
二分
对边长进行二分,每次检查$\frac{w}{a} * \frac{h}{a}$是否大于等于k。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| #include<iostream>
using namespace std;
const int N = 1e5 + 10;
pair<int, int> q[N];
int n, k;
bool check(int x)
{
int cnt = 0;
for(int i = 0; i < n; i ++)
cnt += (q[i].first / x) * (q[i].second / x);
return (cnt >= k ? 1 : 0);
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> k;
for(int i = 0; i < n; i ++) cin >> q[i].first >> q[i].second;
int l = 1, r = 1e5;
int ans = 0;
while(l < r){
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l << '\n';
return 0;
}
|
S. 让我们打开天窗说亮话吧#
图论,多源最短路
观察数据范围发现两点间最短路可以跑floyd。
最短路中去边不好操作,考虑离线逆序处理查询,将去边变为加边。
假设在u,v间加边。设x,y间距离原本为d(x, y),可以更新为x -> u -> v -> y,d(x, u) + w(u, v) + d(v, y)。
题目限制操作一数量最多为300,复杂度为o($n^3$)。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
| #include<iostream>
#include<algorithm>
#include<random>
#include<cstdlib>
#include<vector>
#include<cstring>
#include<climits>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 310, M = N * N / 2;
int n, m, q;
LL d[N][N];
struct road
{
int u, v, w;
}r[M];
struct query
{
char op;
int a, b;
};
void floyd()
{
for(int k = 1; k <= n; k ++)
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
void update(int u, int v)
{
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
d[i][j] = min({d[i][j], d[i][u] + d[u][v] + d[v][j], d[i][v] + d[v][u] + d[u][j]});
}
void solve()
{
cin >> n >> m >> q;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
d[i][j] = (i == j ? 0 : 1e18);
for(int i = 1, u, v, w; i <= m; i ++)
cin >> u >> v >> w, d[u][v] = d[v][u] = min(d[u][v], (LL)w), r[i] = {u, v, w};
vector<query> vq;
for(int i = 1; i <= q; i ++){
char op;
int a, b = 0;
cin >> op >> a;
if(op == 'D'){
auto [u, v, w] = r[a];
d[u][v] = d[v][u] = 1e18;
}
else cin >> b;
vq.push_back({op, a, b});
}
floyd();
reverse(vq.begin(), vq.end());
vector<LL> ans;
for(auto [op, a, b] : vq){
if(op == 'D'){
auto [u, v, w] = r[a];
d[u][v] = d[v][u] = min(d[u][v], (LL)w);
update(u, v);
continue;
}
ans.push_back((d[a][b] >= 1e18 ? -1 : d[a][b]));
}
reverse(ans.begin(), ans.end());
for(auto x : ans) cout << x << '\n';
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
T. 关于acm竞赛中题目名字越长就越有可能是签到题这件事#
并查集,平衡二叉树,启发式合并
需要在并查集中维护一种数据结构,支持:合并,插入,按序查询
开n颗平衡树,对于操作1,用并查集进行合并两颗树,将小树合并至大树。
平衡树可手写splay,使用pbds库的tree结构需要使用速度更快的rb_tree_tag。
均摊时间复杂度o(nlongn)
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
| #include<iostream>
#include<algorithm>
#include<random>
#include<cstdlib>
#include<vector>
#include<cstring>
#include<climits>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/trie_policy.hpp>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
#define lowbit(x) (x&-x)
#define first fi
#define second se
const int N = 2e5 + 10;
int n, q;
__gnu_pbds::tree<int,
__gnu_pbds::null_type,
greater<int>,
__gnu_pbds::rb_tree_tag,
__gnu_pbds::tree_order_statistics_node_update> st[N];
struct DSU
{
int p[N];
void init()
{
for(int i = 0; i <= n; i ++) p[i] = i;
}
int find(int x)
{
return p[x] == x ? x : (p[x] = find(p[x]));
}
void merge(int a, int b)
{
int fa = find(a), fb = find(b);
if(fa == fb) return ;
if(st[fa].size() > st[fb].size()) swap(fa, fb);
p[fa] = fb;
for(auto x : st[fa]) st[fb].insert(x);
st[fa].clear();
}
}dsu;
void solve()
{
cin >> n >> q;
dsu.init();
for(int i = 1; i <= n; i ++) st[i].insert(i);
while(q --){
char op;
int n1, n2;
cin >> op >> n1 >> n2;
if(op == 'C') dsu.merge(n1, n2);
else{
n1 = dsu.find(n1);
cout << (st[n1].size() >= n2 ? *st[n1].find_by_order(n2 - 1) : -1) << '\n';
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
U. 清场#
dfs
注意到n非常小,直接用dfs枚举所有攻击的情况。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define a first
#define h second
int n;
PII f[10];
int vis[10];
bool check()
{
for(int i = 1; i <= n; i ++)
if(f[i].h > 0) return 0;
return 1;
}
bool ok;
void dfs()
{
if(check()){
ok = 1;
return ;
}
for(int i = 1; i <= n; i ++){
if(check()) break;
if(f[i].h <= 0 || !f[i].a || vis[i]) continue;
for(int j = 1; j <= n; j ++){
if(i == j || f[j].h <= 0) continue;
if(check()) break;
vis[i] = 1;
f[i].h -= f[j].a;
f[j].h -= f[i].a;
dfs();
vis[i] = 0;
f[i].h += f[j].a;
f[j].h += f[i].a;
}
}
}
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> f[i].a >> f[i].h;
dfs();
cout << (ok ? "yes" : "no");
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|
V. 六度分隔理论#
并查集
并查集维护朋友关系及一个集合中的最大值,查询时根据两人是否在同一集合。
ac code#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| #include<iostream>
#include<algorithm>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define lowbit(x) (x&-x)
#define fi first
#define se second
const int N = 5e3 + 10;
int p[N], sz[N], c[N], mx[N];
int n, m, q;
void init()
{
for(int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
}
inline int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
void merge(int x, int y)
{
x = find(x), y = find(y);
if(x == y) return ;
if(sz[x] < sz[y]) swap(x, y);
p[y] = x, mx[x] = max(mx[x], mx[y]);
sz[x] += sz[y];
}
void solve()
{
cin >> n;
init();
for(int i = 1; i <= n; i ++) cin >> c[i], mx[i] = c[i];
cin >> m;
while(m --){
int u, v; cin >> u >> v;
merge(u, v);
}
cin >> q;
while(q --){
int u, v; cin >> u >> v;
int fu = find(u), fv = find(v);
if(fu == fv) cout << c[u] + c[v] << '\n';
else cout << mx[fu] + mx[fv] << '\n';
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Case = 1;
//cin >> Case;
while(Case --) solve();
return 0;
}
|