Compare commits
27
Commits
6dd6508386
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fde967ca1 | ||
|
|
9c18114c70 | ||
|
|
a9ab81ba6b | ||
|
|
8453dca92e | ||
|
|
6852bea34c | ||
|
|
c5eebf5252 | ||
|
|
8e1bfd9d9e | ||
|
|
4b50c059cd | ||
|
|
ad876116a5 | ||
|
|
209d5715a5 | ||
|
|
bde443aa2e | ||
|
|
47e9acfb6a | ||
|
|
ed0d5cf6e7 | ||
|
|
2e796fa148 | ||
|
|
2fd0baf3ab | ||
|
|
cfd4039a68 | ||
|
|
399e5e031a | ||
|
|
1dedc9f79d | ||
|
|
3b54c62830 | ||
|
|
9a99b60552 | ||
|
|
43d9b98755 | ||
|
|
dc65d1feb2 | ||
|
|
a92069d382 | ||
|
|
54aa7ffc70 | ||
|
|
2b981db24d | ||
|
|
143cede06f | ||
|
|
0698b03d94 |
No files matched your search
@@ -3,7 +3,7 @@ name: Sync solutions to Wiki
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
branches: [main]
|
||||
paths:
|
||||
- "solutions/**"
|
||||
- ".gitea/workflows/sync-wiki.yml"
|
||||
@@ -73,10 +73,11 @@ jobs:
|
||||
out=wiki/_Sidebar.md
|
||||
|
||||
# 收集 solutions 下所有 md(相对路径,去掉扩展名),按路径排序
|
||||
# 用 -V 做自然排序:P1000 < P2000 < P10000,而不是字典序的 P10000 < P2000
|
||||
mapfile -t items < <(
|
||||
find solutions -type f -name '*.md' -printf '%P\n' \
|
||||
| sed 's/\.md$//' \
|
||||
| sort
|
||||
| sort -V
|
||||
)
|
||||
|
||||
{
|
||||
|
||||
+3
-1
@@ -8,4 +8,6 @@
|
||||
!*.md
|
||||
!.gitea
|
||||
!.gitea/**
|
||||
!.clang-format
|
||||
!.clang-format
|
||||
!article
|
||||
!article/*.md
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n, m, k;
|
||||
long long x, y;
|
||||
int a[200005];
|
||||
int b, preb;
|
||||
int pos[200005];
|
||||
bool k_is_better;
|
||||
vector<int> mor;
|
||||
long long del(int pre, int todo)
|
||||
{
|
||||
if (todo <= pre)
|
||||
return -1;
|
||||
if (todo == pre + 1)
|
||||
return 0;
|
||||
mor.clear();
|
||||
for (int j = pre + 1; j <= todo - 1; ++j)
|
||||
if (a[j] > max(a[todo], a[pre]))
|
||||
mor.push_back(j);
|
||||
if (!mor.empty() && (todo - pre - 1) < k) // 如果有大数且长度不足以运行一次 k 则不存在
|
||||
return -1;
|
||||
if (k_is_better)
|
||||
{
|
||||
return ((todo - pre - 1) % k) * y + ((todo - pre - 1) / k) * x; // 先用 y 移除多余的数,最后用多个 k 直接删完
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mor.empty())
|
||||
return (todo - pre - 1 - k) * y + x; // 用一次k清除最大数,其余用y
|
||||
else
|
||||
return (todo - pre - 1) * y; // 全部用y
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
scanf("%d%d%lld%d%lld", &n, &m, &x, &k, &y);
|
||||
k_is_better = x < (k * y);
|
||||
for (int i = 1; i <= n; ++i)
|
||||
{
|
||||
scanf("%d", &a[i]);
|
||||
pos[a[i]] = i;
|
||||
}
|
||||
long long ans = 0;
|
||||
for (int i = 1; i <= m; ++i)
|
||||
{
|
||||
scanf("%d", &b);
|
||||
int todo = pos[b], pre = 0;
|
||||
if (i != 1)
|
||||
pre = pos[preb];
|
||||
long long d = del(pre, todo);
|
||||
if (d == -1ll)
|
||||
{
|
||||
printf("-1\n");
|
||||
return 0;
|
||||
}
|
||||
ans += d;
|
||||
preb = b;
|
||||
}
|
||||
long long d = del(pos[b], n + 1);
|
||||
if (d == -1ll)
|
||||
{
|
||||
printf("-1\n");
|
||||
return 0;
|
||||
}
|
||||
printf("%lld\n", ans + d);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
若 k 删除更优,先删到能被 k 整除的长度,则先 k 删除,最后运行多次 k 删除
|
||||
len % k
|
||||
若 1 删除更优,先用 k 删除删去大于两边的,最后用 1 删除
|
||||
7 2
|
||||
3 3 1
|
||||
5 7 0 3 1 6 4
|
||||
5 4
|
||||
|
||||
输出 5
|
||||
*/
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
# CF1380D Berserk And Fireball
|
||||
|
||||
## 题目描述
|
||||
|
||||
有 $n$ 个战士站成一排,第 $i$ 个战士的战力是 $a_i$。所有战士的战力都是两两不同的。
|
||||
|
||||
你可以使用两种类型的咒语:
|
||||
|
||||
1. 火球术:你可以消耗 $x$ 点法力值来干掉连续的 $k$ 个战士(你必须干掉正好 $k$ 个,而不能干掉 $\le k$ 个)。
|
||||
|
||||
2. 狂暴术:你可以消耗 $y$ 点法力值,选择站在一起的两个战士使他们展开决斗,战力较弱的那个战士将会被干掉。
|
||||
|
||||
我们来举个例子,假设有 $7$ 个战士,其战力分别为 $[2,3,7,8,11,5,4]$,且此时的$k=3$($k$ 的定义详见火球术)。如果你对战力为 $8$ 与 $11$ 的两个战士施加狂暴术,剩下战士的战力将会变成 $[2,3,7,11,5,4]$(战力为 $8$ 的战士在决斗中战死)。然后如果我们对战力为 $[7,11,5]$ 的战士施加火球术,剩下战士的战力将会变成 $[2,3,4]$。
|
||||
|
||||
你想要组建一支军队,因此你想要将所有战士战力的序列从 $a_1,a_2,\cdots,a_n$ 变为 $b_1,b_2,\cdots,b_m$。试计算你所需的最少法力值。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行两个整数 $n,m (1\le n,m\le 2\cdot 10^5)$ ——序列 $a$ 的长度和序列 $b$ 的长度。
|
||||
|
||||
第二行三个整数 $x,k,y (1\le x,y\le 10^9,1\le k\le n)$ ——火球术消耗的法力值,火球术的范围和狂暴术消耗的法力值。
|
||||
|
||||
第三行 $n$ 个整数 $a_1,a_2,…,a_n (1\le a_i\le n)$。保证 $a_i$ 是两两不同的。
|
||||
|
||||
第四行 $m$ 个整数 $b_1,b_2,…,b_m(1\le b_i\le n)$。保证 $b_i$ 是两两不同的。
|
||||
|
||||
## 输出格式
|
||||
|
||||
一行一个整数,即将序列从 $a_1,a_2,\cdots,a_n$ 变为 $b_1,b_2,\cdots,b_m$所需的最少法力值。如果无法完成变换,则输出$-1$。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5 2
|
||||
5 2 3
|
||||
3 1 4 5 2
|
||||
3 5
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
8
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
4 4
|
||||
5 1 4
|
||||
4 3 1 2
|
||||
2 4 3 1
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
-1
|
||||
```
|
||||
|
||||
## 输入输出样例 #3
|
||||
|
||||
### 输入 #3
|
||||
|
||||
```
|
||||
4 4
|
||||
2 1 11
|
||||
1 3 2 4
|
||||
1 3 2 4
|
||||
```
|
||||
|
||||
### 输出 #3
|
||||
|
||||
```
|
||||
0
|
||||
```
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
set<int> s;
|
||||
map<int, int> rev;
|
||||
int n;
|
||||
int tmp;
|
||||
int main(void) {
|
||||
scanf("%d%d", &n, &tmp), s.insert(tmp), rev[tmp] = 1;
|
||||
for(int i = 2; i <= n; i++) {
|
||||
scanf("%d", &tmp), s.insert(tmp), rev[tmp] = i;
|
||||
auto lb = s.lower_bound(tmp), ub = s.upper_bound(tmp);
|
||||
int minval = INT_MAX, ind = 0;
|
||||
if(lb != s.begin()) {
|
||||
--lb;
|
||||
if(abs(tmp - *lb) < minval)
|
||||
minval = abs(tmp - *lb), ind = rev[*lb];
|
||||
}
|
||||
if(ub != s.end())
|
||||
if(abs(tmp - *ub) < minval)
|
||||
minval = abs(tmp - *ub), ind = rev[*ub];
|
||||
printf("%d %d\n", minval, ind);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# P10466 邻值查找
|
||||
|
||||
## 题目描述
|
||||
|
||||
给定一个长度为 $n$ 的序列 $A$,$A$ 中的数各不相同。
|
||||
|
||||
对于 $A$ 中的每一个数 $A_i$,求:
|
||||
|
||||
$\min_{1 \le j <i}|A_i-A_j|$
|
||||
|
||||
以及令上式取到最小值的 $j$(记为 $P_i$)。若最小值点不唯一,则选择使 $A_j$ 较小的那个。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行输入整数 $n$,代表序列长度。
|
||||
|
||||
第二行输入 $n$ 个整数 $A_1 \sim A_n$,代表序列的具体数值,数值之间用空格隔开。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出共 $n-1$ 行,每行输出两个整数,数值之间用空格隔开。
|
||||
|
||||
分别表示当 $i$ 取 $2 \sim n$ 时,对应的 $\min_{1 \le j <i}|A_i-A_j|$ 和 $P_i$ 的值。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
3
|
||||
1 5 3
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
4 1
|
||||
2 1
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
对于 $30\%$ 的数据 $n \le 100$。
|
||||
|
||||
对于 $70\%$ 的数据 $n \le 10^4$。
|
||||
|
||||
对于 $100\%$ 的数据 $n \le 10^5,|A_i| \le 10^9$。
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int mod = 1145141923;
|
||||
int n, m;
|
||||
int a[1000005];
|
||||
unordered_map<int, bool> ma;
|
||||
int _0;
|
||||
int main() {
|
||||
scanf("%d%d", &n, &m);
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
scanf("%d", &a[i]);
|
||||
if(a[i]) {
|
||||
if(!ma[a[i]]) ma[a[i]] = 1;
|
||||
else {
|
||||
printf("0\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
_0++;
|
||||
}
|
||||
}
|
||||
long long ans = 1;
|
||||
for(int i = m - n + _0; i > m - n; --i) {
|
||||
ans = (ans * i) % mod;
|
||||
}
|
||||
printf("%lld\n", ans);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# P11681 [Algo Beat Contest 001 C] Creating a Queue
|
||||
|
||||
## 题目背景
|
||||
|
||||
| Problem | Score | Idea | Std | Data | Check | Solution |
|
||||
| :---------------------------------: | :---: | :---------------------------------------------------: | :----------------------------------------------------------: | :---------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
| $\text{C - Creating a Queue}$ | $400$ | [joe_zxq](https://www.luogu.com.cn/user/623577) | [fanchuanyu](https://www.luogu.com.cn/user/706256) & [joe_zxq](https://www.luogu.com.cn/user/623577) | [joe_zxq](https://www.luogu.com.cn/user/623577) | [remmymilkyway](https://www.luogu.com.cn/user/551981) | [Link](https://www.luogu.com.cn/article/7r5l2cag) by [joe_zxq](https://www.luogu.com.cn/user/623577) |
|
||||
|
||||
## 题目描述
|
||||
|
||||
给定一个长度为 $N$ 的非负整数序列 $A$。
|
||||
|
||||
现在你需要用 $1\sim M$ 之间的正整数替换所有序列 $A$ 中的 $0$,使得对于其中的任何一段长度大于等于 $2$ 的子数组,不能存在唯一众数。
|
||||
|
||||
> 子数组:在一个数组中,选择一些连续的元素组成的新数组。
|
||||
>
|
||||
> 唯一众数:众数指的是一个数字序列中出现次数最多的元素。如果一个数字序列众数只有一个,我们称这个序列有唯一众数。
|
||||
|
||||
求有多少种不同方案,答案对 $1145141923$ 取模。两种方案称为不同,当且仅当替换后的序列至少有一位上的数不同。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行包含两个正整数 $N$ 和 $M$,表示序列的长度和替换数的最大限度。
|
||||
|
||||
第二行包含 $N$ 个非负整数,表示序列 $A$ 的元素。
|
||||
|
||||
## 输出格式
|
||||
|
||||
一行一个非负整数,表示方案的数量,答案对 $1145141923$ 取模。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
2 3
|
||||
1 0
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
2
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
4 1046
|
||||
114 514 191 981
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
1
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
#### 样例解释 #1
|
||||
|
||||
有 $2$ 个满足条件的序列,分别为 $\{1,2\}$ 和 $\{1,3\}$。
|
||||
|
||||
#### 样例解释 #2
|
||||
|
||||
序列已经完全固定,本身就是一种合法的序列,于是答案为 $1$。
|
||||
|
||||
#### 数据范围
|
||||
|
||||
对于 $100\%$ 的数据,保证 $1 \le N \le 10^6$,$1 \le M \le 10^9$,$0 \le A_i \le M$。
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n;
|
||||
vector<int> chi[100005];
|
||||
int fa[100005][25];
|
||||
int minc[100005][25];
|
||||
int q;
|
||||
int a;
|
||||
void pre(int now) {
|
||||
for(int i = 1; i <= 20; ++i) {
|
||||
fa[now][i] = fa[fa[now][i - 1]][i - 1];
|
||||
}
|
||||
for(int i : chi[now]) {
|
||||
pre(i);
|
||||
}
|
||||
for(int i = 1; i <= 20; ++i) {
|
||||
minc[now][i] = minc[minc[now][i - 1]][i - 1];
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
scanf("%d%d", &n, &q);
|
||||
fa[1][0] = 1;
|
||||
for(int i = 2; i <= n; ++i) {
|
||||
scanf("%d", &fa[i][0]);
|
||||
chi[fa[i][0]].push_back(i);
|
||||
}
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
minc[i][0] = INT_MAX;
|
||||
for(int j : chi[i]) {
|
||||
minc[i][0] = min(minc[i][0], j);
|
||||
}
|
||||
if(minc[i][0] == INT_MAX) minc[i][0] = i;
|
||||
}
|
||||
pre(1);
|
||||
while(q--) {
|
||||
int s, k;
|
||||
scanf("%d%d", &s, &k);
|
||||
for(int i = 1; i <= k; ++i) {
|
||||
scanf("%d", &a);
|
||||
if(a > 0) {
|
||||
for(int j = 20; j >= 0; --j) {
|
||||
if(a >= (1 << j)) {
|
||||
a -= (1 << j);
|
||||
s = fa[s][j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
a = -a;
|
||||
for(int j = 20; j >= 0; --j) {
|
||||
if(a >= (1 << j)) {
|
||||
a -= (1 << j);
|
||||
s = minc[s][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// printf("111: %d\n", fa[5][0]);
|
||||
printf("%d\n", s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
# P13019 [GESP202506 八级] 树上旅行
|
||||
|
||||
## 题目背景
|
||||
|
||||
对应的选择、判断题:<https://ti.luogu.com.cn/problemset/1188>
|
||||
|
||||
## 题目描述
|
||||
|
||||
给定一棵有 $ n $ 个结点的 **有根树**,结点依次以 $1,2,\dots,n$ 编号,其中根结点的编号为 $1$。
|
||||
|
||||
小 A 计划在这棵有根树上进行 $q$ 次旅行。在第 $i$ 次旅行中,小 A 首先选定结点 $s_i$ 作为起点,并移动若干次。移动分为以下两种:
|
||||
|
||||
1. 移动至当前结点的父结点。特殊地,如果当前位于根结点,则不进行移动。
|
||||
2. 移动至当前结点的所有子结点中**编号最小**的结点。特殊地,如果当前位于叶子结点,则不进行移动。
|
||||
|
||||
由于移动次数可能很大,对于第 $i$ 次旅行,旅行中的移动以 $k_i$ 个不为零的整数构成的序列 $a_{i,1}, a_{i,2}, \dots, a_{i,k_i}$ 表示。对 $a_{i,j}$,若 $a_{i,j} > 0$ 则代表进行 $a_{i,j}$ 次第一种移动;若 $a_{i,j} < 0$ 则代表进行 $-a_{i,j}$ 次第二种移动。根据给出的序列从左至右完成所有移动后,小 A 所在的结点即是旅行的**终点**。
|
||||
|
||||
给定每次旅行的起点与移动序列,请你求出旅行终点的结点编号。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行,两个正整数 $n, q$,分别表示有根树的结点数量,以及旅行次数。
|
||||
|
||||
第二行,$n-1$ 个整数 $p_2, p_3, \dots, p_n$,其中 $p_i$ 表示结点 $i$ 的父结点编号。
|
||||
|
||||
接下来 $2q$ 行中的第 $2i-1$ 行($1 \leq i \leq q$)包含两个正整数 $s_i, k_i$,分别表示第 $i$ 次旅行的起点编号,以及移动序列的长度。第 $2i$ 行包含 $k_i$ 个整数 $a_{i,1}, a_{i,2}, \dots, a_{i,k_i}$,表示移动序列。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出共 $q$ 行,第 $i$ 行包含一个整数,表示第 $i$ 次旅行终点的结点编号。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5 4
|
||||
1 1 2 2
|
||||
3 3
|
||||
1 -1 -1
|
||||
2 5
|
||||
1 -1 1 -1 1
|
||||
5 8
|
||||
1 1 1 -1 -1 -1 -1 -1
|
||||
5 3
|
||||
-1 -1 1
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
4
|
||||
1
|
||||
4
|
||||
2
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
8 3
|
||||
5 4 2 1 3 6 6
|
||||
8 1
|
||||
8
|
||||
8 2
|
||||
8 -8
|
||||
8 3
|
||||
8 -8 8
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
1
|
||||
7
|
||||
1
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
| 子任务编号 | 测试点占比 | $n$ | $q$ | $\sum k_i$ | 特殊性质 |
|
||||
|:-:|:-:|:-:|:-:|:-:|:-:|
|
||||
| $1$ | $20\%$ | $\leq 100$ | $\leq 100$ | $\leq 1000$ | 保证 $a_{i,j}$ 为 $1$ 或 $-1$ |
|
||||
| $2$ | $20\%$ | $\leq 10^4$ | $\leq 10^4$ | $\leq 4 \times 10^4$ | 仅包含第一种移动 |
|
||||
| $3$ | $20\%$ | $\leq 10^4$ | $\leq 10^4$ | $\leq 4 \times 10^4$ | 仅包含第二种移动 |
|
||||
| $4$ | $40\%$ | $\leq 10^5$ | $\leq 2 \times 10^4$ | $\leq 10^5$ | - |
|
||||
|
||||
对于所有测试点,保证:
|
||||
|
||||
- $1 \leq n \leq 10^5$
|
||||
- $1 \leq q \leq 2 \times 10^4$
|
||||
- $1 \leq p_i \leq n$
|
||||
- $1 \leq s_i \leq n$
|
||||
- $k_i \geq 1$ 且 $\sum k_i \leq 10^5$
|
||||
- $1 \leq |a_{i,j}| \leq n$
|
||||
@@ -0,0 +1,156 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n;
|
||||
vector<pair<int, int>> fri[200005];
|
||||
pair<int, int> edge[200005];
|
||||
int a[200005];
|
||||
int fa[200005];
|
||||
int dfn[200005];
|
||||
int nowdfn;
|
||||
int cnt[200005];
|
||||
int son[200005];
|
||||
int top[200005];
|
||||
int dep[200005];
|
||||
int m;
|
||||
struct SEG{
|
||||
int num[3][800005];
|
||||
bool lt[800005];
|
||||
void pu(int now, int op) {
|
||||
if(op == 0) num[op][now] = num[op][now * 2] + num[op][now * 2 + 1];
|
||||
else if(op == 1) num[op][now] = max(num[op][now * 2], num[op][now * 2 + 1]);
|
||||
else num[op][now] = min(num[op][now * 2], num[op][now * 2 + 1]);
|
||||
}
|
||||
void pu(int now) {pu(now, 0), pu(now, 1), pu(now, 2);}
|
||||
void dorev(int now) {
|
||||
lt[now] ^= 1;
|
||||
num[0][now] = -num[0][now];
|
||||
int tmp = num[1][now];
|
||||
num[1][now] = -num[2][now];
|
||||
num[2][now] = -tmp;
|
||||
}
|
||||
void pd(int now, int nl, int nr) {
|
||||
if(!lt[now]) return;
|
||||
dorev(now * 2);
|
||||
dorev(now * 2 + 1);
|
||||
lt[now] = 0;
|
||||
}
|
||||
void edit(int now, int nl, int nr, int l, int nn) {
|
||||
if(l < nl || l > nr) return;
|
||||
if(nl == nr) {
|
||||
num[0][now] = nn, num[1][now] = nn, num[2][now] = nn;
|
||||
return;
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
edit(now * 2, nl, nmid, l, nn);
|
||||
edit(now * 2 + 1, nmid + 1, nr, l, nn);
|
||||
pu(now);
|
||||
}
|
||||
void rev(int now, int nl, int nr, int l, int r) {
|
||||
if(nr < l || nl > r) return;
|
||||
if(l <= nl && nr <= r) {
|
||||
dorev(now);
|
||||
return;
|
||||
}
|
||||
pd(now, nl, nr);
|
||||
int nmid = (nl + nr) >> 1;
|
||||
rev(now * 2, nl, nmid, l, r);
|
||||
rev(now * 2 + 1, nmid + 1, nr, l, r);
|
||||
pu(now);
|
||||
}
|
||||
int query(int now, int nl, int nr, int l, int r, int op) {
|
||||
if(nr < l || nl > r) return (op==2)?INT_MAX:((op==1)?INT_MIN:0);
|
||||
if(l <= nl && nr <= r) {
|
||||
return num[op][now];
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
if(op == 0) return query(now * 2, nl, nmid, l, r, op) + query(now * 2 + 1, nmid + 1, nr, l, r, op);
|
||||
else if(op == 1) return max(query(now * 2, nl, nmid, l, r, op), query(now * 2 + 1, nmid + 1, nr, l, r, op));
|
||||
else return min(query(now * 2, nl, nmid, l, r, op), query(now * 2 + 1, nmid + 1, nr, l, r, op));
|
||||
}
|
||||
}seg;
|
||||
void dfs1(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
for(pair<int, int> i : fri[now]) {
|
||||
if(i.second == from) continue;
|
||||
a[i.second] = i.first; // 边权转点权
|
||||
fa[i.second] = now;
|
||||
dep[i.second] = dep[now] + 1;
|
||||
dfs1(i.second, now);
|
||||
cnt[now] += cnt[i.second];
|
||||
if(cnt[i.second] > cnt[son[now]]) son[now] = i.second;
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from) {
|
||||
dfn[now] = ++nowdfn;
|
||||
seg.edit(1, 1, n, nowdfn, a[now]);
|
||||
top[now] = from;
|
||||
if(son[now]) dfs2(son[now], from);
|
||||
for(pair<int, int> i : fri[now]) {
|
||||
if(i.second == son[now] || i.second == fa[now]) continue;
|
||||
dfs2(i.second, i.second);
|
||||
}
|
||||
}
|
||||
void rev(int u, int v) {
|
||||
while(top[u] != top[v]) {
|
||||
if(dep[top[u]] < dep[top[v]]) swap(u, v);
|
||||
seg.rev(1, 1, n, dfn[top[u]], dfn[u]);
|
||||
u = fa[top[u]];
|
||||
}
|
||||
if(dep[u] < dep[v]) swap(u, v);
|
||||
if(dfn[v] + 1 <= dfn[u])
|
||||
seg.rev(1, 1, n, dfn[v] + 1, dfn[u]);
|
||||
}
|
||||
int f(int u, int v, int op) {
|
||||
int ans = 0;
|
||||
if(op == 1) ans = INT_MIN;
|
||||
if(op == 2) ans = INT_MAX;
|
||||
while(top[u] != top[v]) {
|
||||
if(dep[top[u]] < dep[top[v]]) swap(u, v);
|
||||
if(op == 0) ans += seg.query(1, 1, n, dfn[top[u]], dfn[u], 0);
|
||||
else if(op == 1) ans = max(ans, seg.query(1, 1, n, dfn[top[u]], dfn[u], 1));
|
||||
else ans = min(ans, seg.query(1, 1, n, dfn[top[u]], dfn[u], 2));
|
||||
u = fa[top[u]];
|
||||
}
|
||||
if(dep[u] < dep[v]) swap(u, v);
|
||||
if(dfn[v] + 1 <= dfn[u]) {
|
||||
if(op == 0) ans += seg.query(1, 1, n, dfn[v] + 1, dfn[u], 0);
|
||||
else if(op == 1) ans = max(ans, seg.query(1, 1, n, dfn[v] + 1, dfn[u], 1));
|
||||
else ans = min(ans, seg.query(1, 1, n, dfn[v] + 1, dfn[u], 2));
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d", &n);
|
||||
for(int i = 1, u, v, w; i < n; ++i) {
|
||||
scanf("%d%d%d", &u, &v, &w);
|
||||
u++, v++;
|
||||
fri[u].push_back({w, v});
|
||||
fri[v].push_back({w, u});
|
||||
edge[i] = {u, v};
|
||||
}
|
||||
dfs1(1, 0);
|
||||
dfs2(1, 1);
|
||||
scanf("%d", &m);
|
||||
while(m--) {
|
||||
char op[5];
|
||||
int u, v;
|
||||
scanf("%s%d%d", op, &u, &v);
|
||||
if(op[0] == 'C') {
|
||||
pair<int, int> ed = edge[u];
|
||||
if(dep[ed.first] > dep[ed.second]) u = ed.first;
|
||||
else u = ed.second;
|
||||
seg.edit(1, 1, n, dfn[u], v);
|
||||
} else if(op[0] == 'N') {
|
||||
rev(u + 1, v + 1);
|
||||
} else if(op[0] == 'S') {
|
||||
printf("%d\n", f(u + 1, v + 1, 0));
|
||||
} else if(op[1] == 'A') {
|
||||
printf("%d\n", f(u + 1, v + 1, 1));
|
||||
} else {
|
||||
printf("%d\n", f(u + 1, v + 1, 2));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
# P1505 [国家集训队] 旅游
|
||||
|
||||
## 题目背景
|
||||
|
||||
Ray 乐忠于旅游,这次他来到了 T 城。T 城是一个水上城市,一共有 $n$ 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有 $n-1$ 座桥。
|
||||
|
||||
Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度 $w$,也就是说,Ray 经过这座桥会增加 $w$ 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。
|
||||
|
||||
现在,Ray 想让你帮他计算从 $u$ 景点到 $v$ 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。
|
||||
|
||||
## 题目描述
|
||||
|
||||
给定一棵 $n$ 个节点的树,边带权,点的编号为 $0 \sim n-1$,需要支持五种操作:
|
||||
|
||||
- `C i w` 将输入的第 $i$ 条边权值改为 $w$;
|
||||
- `N u v` 将 $u,v$ 节点之间的边权都变为相反数;
|
||||
- `SUM u v` 询问 $u,v$ 节点之间边权和;
|
||||
- `MAX u v` 询问 $u,v$ 节点之间边权最大值;
|
||||
- `MIN u v` 询问 $u,v$ 节点之间边权最小值。
|
||||
|
||||
保证任意时刻所有边的权值都在 $[-1000,1000]$ 内。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行一个正整数 $n$,表示节点个数。
|
||||
接下来 $n-1$ 行,每行三个整数 $u,v,w$,表示 $u,v$ 之间有一条权值为 $w$ 的边,描述这棵树。
|
||||
然后一行一个正整数 $m$,表示操作数。
|
||||
接下来 $m$ 行,每行表示一个操作。
|
||||
|
||||
## 输出格式
|
||||
|
||||
对于每一个询问操作,输出一行一个整数表示答案。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
3
|
||||
0 1 1
|
||||
1 2 2
|
||||
8
|
||||
SUM 0 2
|
||||
MAX 0 2
|
||||
N 0 1
|
||||
SUM 0 2
|
||||
MIN 0 2
|
||||
C 1 3
|
||||
SUM 0 2
|
||||
MAX 0 2
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
3
|
||||
2
|
||||
1
|
||||
-1
|
||||
5
|
||||
3
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
【数据范围】
|
||||
|
||||
对于 $100\%$ 的数据,$1\le n,m \le 2\times 10^5$。
|
||||
|
||||
2020.02.04 修正了一点数据的错误
|
||||
2020.03.14 加入了一组 hack 数据
|
||||
2020.11.26 加入了一组 hack 数据 By @_Leaving
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n, p, q;
|
||||
int a[2005];
|
||||
int f[2005][2005];
|
||||
bool check(int w) {
|
||||
for(int i = 0; i <= p; ++i) {
|
||||
for(int j = 1; j <= n; ++j) {
|
||||
f[i][j] = 0x7f7f7f7f;
|
||||
}
|
||||
}
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
int s = upper_bound(a + 1, a + n + 1, a[i] - w) - a - 1;
|
||||
int t = upper_bound(a + 1, a + n + 1, a[i] - 2 * w) - a - 1;
|
||||
f[0][i] = f[0][t] + 1;
|
||||
for(int j = 1; j <= p; ++j) {
|
||||
f[j][i] = min(f[j - 1][s], f[j][t] + 1);
|
||||
}
|
||||
}
|
||||
return f[p][n] <= q;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d%d%d", &n, &p, &q);
|
||||
for (int i = 1; i <= n; ++i)
|
||||
{
|
||||
scanf("%d", &a[i]);
|
||||
}
|
||||
if (p + q >= n)
|
||||
{ // 若总数足够多,一个盯一个即可,固以下计算 p + q < 2000
|
||||
printf("1\n");
|
||||
return 0;
|
||||
}
|
||||
sort(a + 1, a + n + 1);
|
||||
int l = 1, r = 1e9;
|
||||
while(l < r) {
|
||||
int mid = l + (r - l) / 2;
|
||||
if(check(mid)) r = mid;
|
||||
else l = mid + 1;
|
||||
}
|
||||
printf("%d\n", l);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
f i, k为仅用 i 个小区间处理完前 k 个点所用最少的大区间个数。
|
||||
|
||||
|
||||
f{i, k} = min(f{i − 1, s}, f{i, t} + 1)
|
||||
*/
|
||||
@@ -0,0 +1,95 @@
|
||||
# P15823 [JOI Open 2013] 观影 / Watching
|
||||
|
||||
## 题目描述
|
||||
|
||||
澳大利亚有许多有趣的文化,例如各种体育运动和种类繁多的动物。你正试图观看在布里斯班的一条道路上举办的许多活动。
|
||||
|
||||
这条道路被划分为 $1\,000\,000\,000$ 个区段。这些区段从西到东编号为 $1, 2, \dots, 1\,000\,000\,000$。你想观看 $N$ 场活动。第 $i$ 场活动将在区段 $A_i$ 上举办。
|
||||
|
||||
为了观看这些活动,你准备了 $P$ 台小型摄像机和 $Q$ 台大型摄像机。你可以选择一个正整数 $w$ 作为拍摄参数。然后,一台小型摄像机可以拍摄**最多**连续 $w$ 个区段,一台大型摄像机可以拍摄**最多**连续 $2w$ 个区段。同一个区段可以被多台摄像机拍摄。你想拍摄所有举办活动的区段。由于预计会有很多人前往活动现场,出于安全考虑,你必须固定摄像机的位置,并且在活动期间不允许移动它们。参数 $w$ 越大,拍摄的成本就越高。因此,你希望最小化 $w$ 的值。
|
||||
|
||||
### 任务
|
||||
|
||||
编写一个程序,根据给定的活动信息和摄像机数量,确定能够拍摄所有活动所在区段所需的最小 $w$ 值。
|
||||
|
||||
## 输入格式
|
||||
|
||||
从标准输入读取以下数据。
|
||||
|
||||
- 输入的第一行包含三个以空格分隔的整数 $N, P, Q$。其中 $N$ 是活动的数量,$P$ 是小型摄像机的数量,$Q$ 是大型摄像机的数量。
|
||||
- 接下来的 $N$ 行中,第 $i$ 行($1 \le i \le N$)包含一个整数 $A_i$,表示第 $i$ 场活动举办的区段编号。
|
||||
|
||||
## 输出格式
|
||||
|
||||
向标准输出写入一个整数,表示能够拍摄所有活动所在区段所需的最小 $w$ 值。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
3 1 1
|
||||
2
|
||||
11
|
||||
17
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
4
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
13 3 2
|
||||
33
|
||||
66
|
||||
99
|
||||
10
|
||||
83
|
||||
68
|
||||
19
|
||||
83
|
||||
93
|
||||
53
|
||||
15
|
||||
66
|
||||
75
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
9
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
### 样例解释
|
||||
|
||||
在第一个样例中,当你选择 $w = 4$ 时,就可以拍摄所有活动所在的区段。例如,你可以用一台小型摄像机拍摄从区段 1 到 3 的区域,用一台大型摄像机拍摄从区段 11 到 18 的区域。
|
||||
|
||||
### 约束条件
|
||||
|
||||
所有输入数据满足以下条件。
|
||||
|
||||
- $1 \le N \le 2000$。
|
||||
- $1 \le P \le 100\,000$。
|
||||
- $1 \le Q \le 100\,000$。
|
||||
- $1 \le A_i \le 1\,000\,000\,000$($1 \le i \le N$)。
|
||||
|
||||
### 子任务
|
||||
|
||||
#### 子任务 1 [50 分]
|
||||
|
||||
- 满足 $N \le 100$。
|
||||
|
||||
#### 子任务 2 [50 分]
|
||||
|
||||
- 无额外约束。
|
||||
|
||||
翻译由 DeepSeek V3.2 完成
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int side(char c) {
|
||||
if (c == 'A' || c == 'B' || c == 'C') return 0;
|
||||
return 1;
|
||||
}
|
||||
int pos(char c) {
|
||||
if (c == 'A') return 0;
|
||||
if (c == 'B') return 1;
|
||||
if (c == 'C') return 2;
|
||||
if (c == 'D') return 0;
|
||||
return 1; // 'F'
|
||||
}
|
||||
int main() {
|
||||
string c1, s1, c2, s2;
|
||||
cin >> c1 >> s1 >> c2 >> s2;
|
||||
bool ans1 = (c1 == c2);
|
||||
bool ans2 = ans1 && (s1.substr(0, 2) == s2.substr(0, 2));
|
||||
char a = s1[2], b = s2[2];
|
||||
bool ans3 = ans2 && (side(a) == side(b));
|
||||
bool ans4 = ans3 && (abs(pos(a) - pos(b)) == 1);
|
||||
cout << ans1 << ans2 << ans3 << ans4 << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
# P17827 [CSP-J 2026] 旅游 / travel(民间数据)
|
||||
|
||||
## 题目描述
|
||||
|
||||
小 R 和小 X 准备坐高铁出门旅游。他们买了两张二等座车票,车票上写着各自的车厢号和座位号。两人希望座位相邻,这样旅途中可以坐在一起。
|
||||
|
||||
他们乘坐的列车由 $17$ 节车厢组成,车厢编号是 `01` 到 `17`。其中,`01` 和 `16` 号车厢是一等座车厢,其余车厢是二等座车厢。两人买的都是二等座车票,座位都在二等座车厢中。每节二等座车厢共有 $18$ 排,每排有 $5$ 个座位。座位号由两位排号和一位大写字母组成,例如 `03C` 表示第 $3$ 排 C 座。每一排的座位按照从左到右的顺序排列,座位字母依次是 `A`、`B`、`C`、`D`、`F`,其中 C 座与 D 座之间是过道,即每排过道左侧的座位序列是 `A`、`B`、`C`,右侧是 `D`、`F`。以下是一节二等座车厢的座位示意图:
|
||||
|
||||
:::align{center}
|
||||

|
||||
:::
|
||||
|
||||
两个座位相邻,当且仅当在同一节车厢的同一排,位于过道的同一侧,且在该侧的座位序列中相邻。
|
||||
|
||||
你需要帮助小 R 依次判断:
|
||||
|
||||
- 两张车票对应的座位是否在同一节车厢;
|
||||
- 两张车票对应的座位是否在同一节车厢的同一排;
|
||||
- 两张车票对应的座位是否在同一节车厢的同一排,且位于过道的同一侧;
|
||||
- 两张车票对应的座位是否相邻。
|
||||
|
||||
## 输入格式
|
||||
|
||||
从文件 `travel.in` 中读入数据。
|
||||
|
||||
输入的第一行包含四个字符串 $c_1,s_1,c_2,s_2$,分别表示小 R 的车票上的车厢号、座位号,以及小 X 的车票上的车厢号、座位号。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出到文件 `travel.out` 中。
|
||||
|
||||
输出一行一个长度为 $4$ 的 `01` 字符串,分别表示四个问题的答案,其中 `1` 代表是,`0` 代表否。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
02 01A 02 01B
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
1111
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
02 01C 02 01A
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
1110
|
||||
```
|
||||
|
||||
## 输入输出样例 #3
|
||||
|
||||
### 输入 #3
|
||||
|
||||
```
|
||||
02 01C 02 01D
|
||||
```
|
||||
|
||||
### 输出 #3
|
||||
|
||||
```
|
||||
1100
|
||||
```
|
||||
|
||||
## 输入输出样例 #4
|
||||
|
||||
### 输入 #4
|
||||
|
||||
```
|
||||
02 02B 02 01A
|
||||
```
|
||||
|
||||
### 输出 #4
|
||||
|
||||
```
|
||||
1000
|
||||
```
|
||||
|
||||
## 输入输出样例 #5
|
||||
|
||||
### 输入 #5
|
||||
|
||||
```
|
||||
02 01A 03 01A
|
||||
```
|
||||
|
||||
### 输出 #5
|
||||
|
||||
```
|
||||
0000
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
### 样例 1 解释
|
||||
|
||||
`02` 号车厢是二等座车厢。`01A` 和 `01B` 在同一节车厢、同一排、过道的同一侧,并且相邻,因此输出 `1111`。
|
||||
|
||||
### 样例 2 解释
|
||||
|
||||
两个座位在同一节车厢、同一排、过道的同一侧,但 `01C` 与 `01A` 中间隔着 `01B`,不相邻,因此输出 `1110`。
|
||||
|
||||
### 数据范围
|
||||
|
||||
对于所有测试数据,均有:
|
||||
|
||||
- $c_1,c_2$ 是 `01` 到 `17` 之间除 `01` 和 `16` 外的两位车厢号;
|
||||
- $s_1,s_2$ 是对应车厢中的合法座位号,即前两位是 `01` 到 `18` 之间的排号,末位是 `A`、`B`、`C`、`D`、`F` 中的一个字母;
|
||||
- 两张车票对应的不是同一个座位,即 $c_1\ne c_2$ 或 $s_1\ne s_2$。
|
||||
|
||||
::cute-table{tuack}
|
||||
| 测试点编号 | 特殊性质 |
|
||||
| :-: | :-: |
|
||||
| $1\sim 4$ | A, B, C |
|
||||
| $5\sim 10$ | A, B |
|
||||
| $11\sim 14$ | A |
|
||||
| $15\sim 17$ | D |
|
||||
| $18\sim 20$ | 无 |
|
||||
|
||||
特殊性质 A:两个座位在同一节车厢,即 $c_1=c_2$。
|
||||
|
||||
特殊性质 B:两个座位在同一排,即 $s_1$ 的前两位与 $s_2$ 的前两位相同。
|
||||
|
||||
特殊性质 C:两个座位在过道的同一侧。
|
||||
|
||||
特殊性质 D:小 R 的座位是 D 座,小 X 的座位是 F 座,即 $s_1$ 的末位字符是 `D`,$s_2$ 的末位字符是 `F`。
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n;
|
||||
long long m;
|
||||
long long a[500005];
|
||||
long long qsum[500005];
|
||||
bool checkb(int mid, long long now, int tot) {
|
||||
return mid * now - (qsum[tot] - qsum[tot - mid]) <= m;
|
||||
}
|
||||
long long check(long long now, int tot) {
|
||||
long long nowm = m;
|
||||
long long ans = 0;
|
||||
int l = 1, r = tot, mid = (l + r) >> 1;
|
||||
while(l < r) {
|
||||
mid = (l + r) >> 1;
|
||||
if(checkb(mid, now, tot)) {
|
||||
l = mid + 1;
|
||||
} else {
|
||||
r = mid;
|
||||
}
|
||||
}
|
||||
while(!checkb(mid, now, tot) && mid >= 1) mid--;
|
||||
while(checkb(mid + 1, now, tot) && mid + 1 <= tot) mid++;
|
||||
return mid;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d%lld", &n, &m);
|
||||
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
|
||||
sort(a + 1, a + n + 1);
|
||||
for(int i = 1; i <= n; ++i) qsum[i] = qsum[i - 1] + a[i];
|
||||
long long ans = 0;
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
if(a[i + 1] == a[i]) continue;
|
||||
ans = max(ans, check(a[i], i));
|
||||
// printf("%d %lld\n", i, check(a[i], i));
|
||||
}
|
||||
printf("%lld\n", ans);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
g++ crystal/crystal.cpp -o crystal/crystal -std=c++14 -O2 -static -Wall && cp crystal/crystal ~ && chmod +x ~/crystal && ~/crystal
|
||||
O(n log n)
|
||||
100pts
|
||||
*/
|
||||
@@ -0,0 +1,95 @@
|
||||
# P17831 [CSP-S 2026] 能量水晶 / crystal(民间数据)
|
||||
|
||||
## 题目描述
|
||||
|
||||
小 R 有 $n$ 颗能量水晶,其中第 $i$ $(1 \le i \le n)$ 颗的能量值为整数 $a_i$。
|
||||
|
||||
小 R 想用其中若干颗能量水晶合成一颗大水晶,用于合成的水晶必须具有相同的能量值。小 R 希望参与合成的水晶尽可能多。他可以进行**至多** $m$ 次操作。每次操作可以任选一颗水晶,将其能量值增加 $1$;同一颗水晶可以被重复选择。
|
||||
|
||||
你需要帮助小 R 求出,进行至多 $m$ 次操作后,他最多能用多少颗能量水晶合成一颗大水晶。
|
||||
|
||||
## 输入格式
|
||||
|
||||
从文件 `crystal.in` 中读入数据。
|
||||
|
||||
输入的第一行包含一个正整数 $n$ 和一个非负整数 $m$,分别表示能量水晶的数量和最多可以进行的操作次数。
|
||||
|
||||
输入的第二行包含 $n$ 个整数 $a_1,a_2,\ldots,a_n$,依次表示每颗能量水晶的能量值。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出到文件 `crystal.out` 中。
|
||||
|
||||
输出一行一个正整数,表示进行至多 $m$ 次操作后,小 R 最多能用多少颗能量水晶合成一颗大水晶。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5 5
|
||||
1 2 4 8 9
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
3
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
5 8
|
||||
-3 -1 2 2 7
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
4
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
### 样例 1 解释
|
||||
|
||||
小 R 有 $5$ 颗能量水晶,能量值分别为 $1,2,4,8,9$。他可以对能量值为 $1$ 和 $2$ 的水晶分别操作 $3$ 次和 $2$ 次,使原来能量值为 $1,2,4$ 的三颗水晶的能量值都变成 $4$,共进行 $5$ 次操作。因此小 R 可以用 $3$ 颗能量水晶合成一颗大水晶。
|
||||
|
||||
### 样例 3
|
||||
|
||||
见题目目录下的 `crystal/3.in` 与 `crystal/3.ans`。
|
||||
|
||||
该样例满足测试点 $8,9$ 的约束条件。
|
||||
|
||||
### 样例 4
|
||||
|
||||
见题目目录下的 `crystal/4.in` 与 `crystal/4.ans`。
|
||||
|
||||
该样例满足测试点 $10 \sim 12$ 的约束条件。
|
||||
|
||||
### 数据范围
|
||||
|
||||
对于所有测试数据,均有:
|
||||
|
||||
- $1 \le n \le 5 \times 10^5$,$0 \le m \le 10^{18}$;
|
||||
- 对于所有 $i$ $(1 \le i \le n)$,均有 $|a_i| \le 10^{12}$。
|
||||
|
||||
::cute-table{tuack}
|
||||
|
||||
| 测试点编号 | $n \le$ | $m \le$ | $\max_{i=1}^{n} \lvert a_i \rvert \le$ | 特殊性质 |
|
||||
| :-: | :-: | :-: | :-: | :-: |
|
||||
| $1,2$ | $5$ | $10$ | $20$ | 无 |
|
||||
| $3 \sim 5$ | $16$ | $1000$ | $20$ | 无 |
|
||||
| $6,7$ | $5000$ | $10^6$ | $100$ | 无 |
|
||||
| $8,9$ | $5000$ | $10^9$ | $10^5$ | 无 |
|
||||
| $10 \sim 12$ | $5 \times 10^5$ | $10^8$ | $100$ | 无 |
|
||||
| $13 \sim 15$ | $5 \times 10^5$ | $10^{18}$ | $10^{12}$ | A |
|
||||
| $16 \sim 18$ | $5 \times 10^5$ | $10^{18}$ | $10^{12}$ | B |
|
||||
| $19,20$ | $5 \times 10^5$ | $10^{18}$ | $10^{12}$ | 无 |
|
||||
|
||||
特殊性质 A:对于所有 $i$ $(1 \le i \le n)$,均有 $a_i=i$。
|
||||
|
||||
特殊性质 B:$a_1,a_2,\ldots,a_n$ 构成等差数列。
|
||||
@@ -0,0 +1,128 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n, m, q;
|
||||
int a[10005];
|
||||
vector<pair<int, pair<int, int>>> edge;
|
||||
vector<pair<int, int>> fri[10005];
|
||||
struct BCJ {
|
||||
int fa[10005];
|
||||
int find(int x) {
|
||||
if (fa[x] == x) return x;
|
||||
return fa[x] = find(fa[x]);
|
||||
}
|
||||
} b;
|
||||
struct SEG {
|
||||
int num[10005 * 4];
|
||||
void init(int now, int nl, int nr) {
|
||||
if (nl == nr) {
|
||||
num[now] = a[nl];
|
||||
return;
|
||||
}
|
||||
int mid = (nl + nr) >> 1;
|
||||
init(now * 2, nl, mid);
|
||||
init(now * 2 + 1, mid + 1, nr);
|
||||
num[now] = min(num[now * 2], num[now * 2 + 1]);
|
||||
}
|
||||
int query(int now, int nl, int nr, int l, int r) {
|
||||
if (nr < l || nl > r) return INT_MAX;
|
||||
if (l <= nl && nr <= r) return num[now];
|
||||
int mid = (nl + nr) >> 1;
|
||||
return min(query(now * 2, nl, mid, l, r), query(now * 2 + 1, mid + 1, nr, l, r));
|
||||
}
|
||||
} seg;
|
||||
int fa[10005];
|
||||
pair<int, int> son[10005];
|
||||
int cnt[10005];
|
||||
int top[10005];
|
||||
int dfn[10005];
|
||||
int dep[10005];
|
||||
int nowdfn;
|
||||
void dfs1(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
for (auto i : fri[now]) {
|
||||
int v = i.second;
|
||||
int w = i.first;
|
||||
if (v == from) continue;
|
||||
fa[v] = now;
|
||||
dep[v] = dep[now] + 1;
|
||||
dfs1(v, now);
|
||||
cnt[now] += cnt[v];
|
||||
if (cnt[son[now].first] < cnt[v]) {
|
||||
son[now].first = v;
|
||||
son[now].second = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from, int w) {
|
||||
dfn[now] = ++nowdfn;
|
||||
top[now] = from;
|
||||
a[dfn[now]] = w;
|
||||
if (son[now].first) {
|
||||
dfs2(son[now].first, from, son[now].second);
|
||||
}
|
||||
for (auto i : fri[now]) {
|
||||
int v = i.second;
|
||||
int ww = i.first;
|
||||
if (v == fa[now] || v == son[now].first) continue;
|
||||
dfs2(v, v, ww);
|
||||
}
|
||||
}
|
||||
int pt(int x, int y) {
|
||||
if (x == y) return INT_MAX;
|
||||
int ans = INT_MAX;
|
||||
while (top[x] != top[y]) {
|
||||
if (dep[top[x]] < dep[top[y]]) swap(x, y);
|
||||
ans = min(ans, seg.query(1, 1, n, dfn[top[x]], dfn[x]));
|
||||
x = fa[top[x]];
|
||||
}
|
||||
if (dep[x] < dep[y]) swap(x, y);
|
||||
if (dfn[y] + 1 <= dfn[x]) {
|
||||
ans = min(ans, seg.query(1, 1, n, dfn[y] + 1, dfn[x]));
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d%d", &n, &m);
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
b.fa[i] = i;
|
||||
}
|
||||
for (int i = 1, u, v, w; i <= m; ++i) {
|
||||
scanf("%d%d%d", &u, &v, &w);
|
||||
edge.push_back({w, {u, v}});
|
||||
}
|
||||
sort(edge.begin(), edge.end(),
|
||||
[](const pair<int, pair<int, int>> &x,
|
||||
const pair<int, pair<int, int>> &y) {
|
||||
return x.first > y.first;
|
||||
});
|
||||
for (auto i : edge) {
|
||||
int w = i.first;
|
||||
int u = i.second.first;
|
||||
int v = i.second.second;
|
||||
if (b.find(u) != b.find(v)) {
|
||||
fri[u].push_back({w, v});
|
||||
fri[v].push_back({w, u});
|
||||
b.fa[b.find(u)] = b.find(v);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
if (!dfn[i]) {
|
||||
dfs1(i, 0);
|
||||
dfs2(i, i, INT_MAX);
|
||||
}
|
||||
}
|
||||
seg.init(1, 1, n);
|
||||
scanf("%d", &q);
|
||||
while (q--) {
|
||||
int x, y;
|
||||
scanf("%d%d", &x, &y);
|
||||
if (b.find(x) != b.find(y)) {
|
||||
printf("-1\n");
|
||||
continue;
|
||||
}
|
||||
int ans = pt(x, y);
|
||||
printf("%d\n", ans == INT_MAX ? -1 : ans);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
# P1967 [NOIP 2013 提高组] 货车运输
|
||||
|
||||
## 题目背景
|
||||
|
||||
NOIP2013 提高组 D1T3
|
||||
|
||||
## 题目描述
|
||||
|
||||
A 国有 $n$ 座城市,编号从 $1$ 到 $n$,城市之间有 $m$ 条双向道路。每一条道路对车辆都有重量限制,简称限重。
|
||||
|
||||
现在有 $q$ 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行有两个用一个空格隔开的整数 $n,m$,表示 A 国有 $n$ 座城市和 $m$ 条道路。
|
||||
|
||||
接下来 $m$ 行每行三个整数 $x, y, z$,每两个整数之间用一个空格隔开,表示从 $x$ 号城市到 $y$ 号城市有一条限重为 $z$ 的道路。
|
||||
注意:$x \neq y$,两座城市之间可能有多条道路。
|
||||
|
||||
接下来一行有一个整数 $q$,表示有 $q$ 辆货车需要运货。
|
||||
|
||||
接下来 $q$ 行,每行两个整数 $x,y$,之间用一个空格隔开,表示一辆货车需要从 $x$ 城市运输货物到 $y$ 城市,保证 $x \neq y$。
|
||||
|
||||
## 输出格式
|
||||
|
||||
共有 $q$ 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
|
||||
如果货车不能到达目的地,输出 $-1$。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
4 3
|
||||
1 2 4
|
||||
2 3 3
|
||||
3 1 1
|
||||
3
|
||||
1 3
|
||||
1 4
|
||||
1 3
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
3
|
||||
-1
|
||||
3
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
对于 $30\%$ 的数据,$1 \le n < 1000$,$1 \le m < 10,000$,$1\le q< 1000$;
|
||||
|
||||
对于 $60\%$ 的数据,$1 \le n < 1000$,$1 \le m < 5\times 10^4$,$1 \le q< 1000$;
|
||||
|
||||
对于 $100\%$ 的数据,$1 \le n < 10^4$,$1 \le m < 5\times 10^4$,$1 \le q< 3\times 10^4 $,$0 \le z \le 10^5$。
|
||||
@@ -0,0 +1,64 @@
|
||||
#include<bits/stdc++.h>
|
||||
#define int long long
|
||||
using namespace std;
|
||||
int n;
|
||||
vector<int> fri[100005];
|
||||
int p[100005];
|
||||
int dfn[100005];
|
||||
int cnt[100005];
|
||||
int nowdfn;
|
||||
struct SEG{
|
||||
int num[400005], lt[400005];
|
||||
void pd(int now, int nl, int nr) {
|
||||
int nmid = (nl + nr) >> 1;
|
||||
num[now * 2] += lt[now] * (nmid - nl + 1);
|
||||
num[now * 2 + 1] += lt[now] * (nr - nmid);
|
||||
lt[now * 2] += lt[now];
|
||||
lt[now * 2 + 1] += lt[now];
|
||||
lt[now] = 0;
|
||||
}
|
||||
void pu(int now) {num[now] = num[now * 2] + num[now * 2 + 1];}
|
||||
void add(int now, int nl, int nr, int l, int r, int nn) {
|
||||
if(nl > r || nr < l) return;
|
||||
if(l <= nl && nr <= r) {
|
||||
num[now] += nn * (nr - nl + 1);
|
||||
lt[now] += nn;
|
||||
return;
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
add(now * 2, nl, nmid, l, r, nn);
|
||||
add(now * 2 + 1, nmid + 1, nr, l, r, nn);
|
||||
pu(now);
|
||||
}
|
||||
int query(int now, int nl, int nr, int l, int r) {
|
||||
if(nl > r || nr < l) return 0;
|
||||
if(l <= nl && nr <= r) return num[now];
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
return query(now * 2, nl, nmid, l, r) + query(now * 2 + 1, nmid + 1, nr, l, r);
|
||||
}
|
||||
}seg;
|
||||
void dfs(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
dfn[now] = ++nowdfn;
|
||||
for(int i : fri[now]) {
|
||||
if(i == from) continue;
|
||||
dfs(i, now);
|
||||
cnt[now] += cnt[i];
|
||||
}
|
||||
}
|
||||
signed main() {
|
||||
scanf("%lld", &n);
|
||||
for(int i = 1, u, v; i < n; ++i) {
|
||||
scanf("%lld%lld", &u, &v);
|
||||
fri[u].push_back(v);
|
||||
fri[v].push_back(u);
|
||||
}
|
||||
dfs(1, 0);
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
scanf("%lld", &p[i]);
|
||||
printf("%lld\n", seg.query(1, 1, n, dfn[p[i]], dfn[p[i]]));
|
||||
seg.add(1, 1, n, dfn[p[i]], dfn[p[i]] + cnt[p[i]] - 1, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
# P2982 [USACO10FEB] Slowing down G
|
||||
|
||||
## 题目描述
|
||||
|
||||
每天,Farmer John 的 $N$ $(1 \le N \le 100{,}000)$ 头奶牛(方便地编号为 $1..N$)都会从牛棚走向各自的私人牧场。牧场形成一棵树,其中牛棚位于牧场 $1$。恰好有 $N-1$ 条无向路径连接这些牧场;直接相连的牧场之间恰好有一条路径。路径 $i$ 连接牧场 $A_i$ 和 $B_i$ $(1 \le A_i \le N, 1 \le B_i \le N)$。
|
||||
|
||||
奶牛 $i$ 拥有一个私人牧场 $P_i$ $(1 \le P_i \le N)$。牛棚的小门一次只能让一头奶牛出去,耐心的奶牛们会等待前一头奶牛到达她的私人牧场。首先,奶牛 $1$ 离开并走向牧场 $P_1$。接着奶牛 $2$ 离开并前往牧场 $P_2$,依此类推。
|
||||
|
||||
当奶牛 $i$ 走向 $P_i$ 时,她可能会经过已经有奶牛在进食的牧场。当一头奶牛出现在某个牧场时,奶牛 $i$ 在穿过该牧场时会比平时走得更慢,以避免打扰她的朋友。
|
||||
|
||||
```cpp
|
||||
考虑以下牧场网络,其中括号中的数字表示牧场的主人。
|
||||
|
||||
1 (3)
|
||||
/ \
|
||||
(1) 4 3 (5)
|
||||
/ \
|
||||
(2) 2 5 (4)
|
||||
|
||||
首先,奶牛 1 走向她的牧场:
|
||||
|
||||
1 (3)
|
||||
/ \
|
||||
[1] 4* 3 (5)
|
||||
/ \
|
||||
(2) 2 5 (4)
|
||||
|
||||
当奶牛 2 走向她的牧场时,她首先进入牛棚的牧场,即牧场 1。
|
||||
然后她绕过牧场 4 中的奶牛 1,最终到达自己的牧场。
|
||||
|
||||
1 (3)
|
||||
/ \
|
||||
[1] 4* 3 (5)
|
||||
/ \
|
||||
[2] 2* 5 (4)
|
||||
|
||||
奶牛 3 根本没走远——她在牛棚的牧场 #1 里闲逛。
|
||||
|
||||
1* [3]
|
||||
/ \
|
||||
[1] 4* 3 (5)
|
||||
/ \
|
||||
[2] 2* 5 (4)
|
||||
|
||||
奶牛 4 在前往牧场 5 的路上,必须在牧场 1 和 4 放慢速度:
|
||||
|
||||
1* [3]
|
||||
/ \
|
||||
[1] 4* 3 (5)
|
||||
/ \
|
||||
[2] 2* 5* [4]
|
||||
|
||||
奶牛 5 因为在牧场 1 遇到奶牛 3 而放慢速度,然后进入自己的私人牧场:
|
||||
|
||||
1* [3]
|
||||
/ \
|
||||
[1] 4* 3*[5]
|
||||
/ \
|
||||
[2] 2* 5* [4]
|
||||
```
|
||||
|
||||
FJ 想知道每头奶牛需要放慢多少次速度。
|
||||
|
||||
## 输入格式
|
||||
|
||||
- 第 1 行:一个整数 $N$。
|
||||
- 第 $2..N$ 行:第 $i+1$ 行包含两个以空格分隔的整数 $A_i$ 和 $B_i$。
|
||||
- 第 $N+1..N+N$ 行:第 $N+i$ 行包含一个整数 $P_i$。
|
||||
|
||||
## 输出格式
|
||||
|
||||
- 第 $1..N$ 行:第 $i$ 行包含奶牛 $i$ 需要放慢速度的次数。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5
|
||||
1 4
|
||||
5 4
|
||||
1 3
|
||||
2 4
|
||||
4
|
||||
2
|
||||
1
|
||||
5
|
||||
3
|
||||
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
0
|
||||
1
|
||||
0
|
||||
2
|
||||
1
|
||||
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
数据范围:$1 \leq A_i, B_i, P_i \leq N \leq 10^5$。
|
||||
@@ -0,0 +1,99 @@
|
||||
#include<bits/stdc++.h>
|
||||
#define int long long
|
||||
using namespace std;
|
||||
int n;
|
||||
int a[300005];
|
||||
int fa[300005];
|
||||
int dfn[300005];
|
||||
int son[300005];
|
||||
int dep[300005];
|
||||
int top[300005];
|
||||
int cnt[300005];
|
||||
vector<int> fri[300005];
|
||||
int dfnnow;
|
||||
struct SEG{
|
||||
int num[1200005], lt[1200005];
|
||||
void pu(int now) {
|
||||
num[now] = num[now * 2] + num[now * 2 + 1];
|
||||
}
|
||||
void pd(int now, int nl, int nr) {
|
||||
int nmid = (nl + nr) >> 1, l = lt[now];
|
||||
num[now * 2] += l * (nmid - nl + 1);
|
||||
num[now * 2 + 1] += l * (nr - nmid);
|
||||
lt[now * 2] += l;
|
||||
lt[now * 2 + 1] += l;
|
||||
lt[now] = 0;
|
||||
}
|
||||
void add(int now, int nl, int nr, int l, int r, int nn) {
|
||||
if(nr < l || nl > r) return;
|
||||
if(l <= nl && nr <= r) {
|
||||
num[now] += (nr - nl + 1) * nn;
|
||||
lt[now] += nn;
|
||||
return;
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
add(now * 2, nl, nmid, l, r, nn);
|
||||
add(now * 2 + 1, nmid + 1, nr, l, r, nn);
|
||||
pu(now);
|
||||
}
|
||||
int query(int now, int nl, int nr, int l, int r) {
|
||||
if(nr < l || nl > r) return 0;
|
||||
if(l <= nl && nr <= r) {
|
||||
return num[now];
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
return query(now * 2, nl, nmid, l, r) + query(now * 2 + 1, nmid + 1, nr, l, r);
|
||||
}
|
||||
}seg;
|
||||
void dfs1(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
for(int i : fri[now]) {
|
||||
if(i == from) continue;
|
||||
fa[i] = now;
|
||||
dep[i] = dep[now] + 1;
|
||||
dfs1(i, now);
|
||||
cnt[now] += cnt[i];
|
||||
if(cnt[son[now]] < cnt[i]) son[now] = i;
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from) {
|
||||
top[now] = from;
|
||||
dfn[now] = ++dfnnow;
|
||||
if(son[now]) dfs2(son[now], from);
|
||||
for(int i : fri[now]) {
|
||||
if(i == fa[now] || i == son[now]) continue;
|
||||
dfs2(i, i);
|
||||
}
|
||||
}
|
||||
void edit(int a, int b, int nn = 1) {
|
||||
while(top[a] != top[b]) {
|
||||
if(dep[top[a]] < dep[top[b]]) swap(a, b);
|
||||
seg.add(1, 1, n, dfn[top[a]], dfn[a], nn);
|
||||
a = fa[top[a]];
|
||||
}
|
||||
if(dep[a] < dep[b]) swap(a, b);
|
||||
seg.add(1, 1, n, dfn[b], dfn[a], nn);
|
||||
}
|
||||
signed main() {
|
||||
scanf("%lld", &n);
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
scanf("%lld", &a[i]);
|
||||
}
|
||||
for(int i = 1, u, v; i < n; ++i) {
|
||||
scanf("%lld%lld", &u, &v);
|
||||
fri[u].push_back(v);
|
||||
fri[v].push_back(u);
|
||||
}
|
||||
dfs1(1, -1);
|
||||
dfs2(1, 1);
|
||||
for(int i = 1; i < n; ++i) {
|
||||
edit(a[i], a[i + 1]);
|
||||
edit(a[i + 1], a[i + 1], -1);
|
||||
}
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
printf("%lld\n", seg.query(1, 1, n, dfn[i], dfn[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# P3258 [JLOI2014] 松鼠的新家
|
||||
|
||||
## 题目描述
|
||||
|
||||
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有 $n$ 个房间,并且有 $n-1$ 根树枝连接,每个房间都可以相互到达,且两个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。
|
||||
|
||||
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去 $a_1$,再去 $a_2$,……,最后到 $a_n$,去参观新家。可是这样会导致重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
|
||||
|
||||
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
|
||||
|
||||
因为松鼠参观指南上的最后一个房间 $a_n$ 是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行一个正整数 $n$,表示房间个数。第二行 $n$ 个正整数,依次描述 $a_1, a_2,\cdots,a_n$。
|
||||
|
||||
接下来 $n-1$ 行,每行两个正整数 $x,y$,表示标号 $x$ 和 $y$ 的两个房间之间有树枝相连。
|
||||
|
||||
## 输出格式
|
||||
|
||||
一共 $n$ 行,第 $i$ 行输出标号为 $i$ 的房间至少需要放多少个糖果,才能让维尼有糖果吃。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5
|
||||
1 4 5 3 2
|
||||
1 2
|
||||
2 4
|
||||
2 3
|
||||
4 5
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
1
|
||||
2
|
||||
1
|
||||
2
|
||||
1
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
对于全部的数据,$2 \le n \le 3 \times 10^5$,$1 \le a_i \le n$。
|
||||
@@ -0,0 +1,73 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n, q;
|
||||
vector<int> fri[100005];
|
||||
int fa[100005];
|
||||
int dep[100005];
|
||||
int top[100005];
|
||||
int son[100005];
|
||||
int cnt[100005];
|
||||
void dfs1(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
for(int i : fri[now]) {
|
||||
if(i == from) continue;
|
||||
fa[i] = now;
|
||||
dep[i] = dep[now] + 1;
|
||||
dfs1(i, now);
|
||||
cnt[now] += cnt[i];
|
||||
if(cnt[son[now]] < cnt[i]) son[now] = i;
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from) {
|
||||
top[now] = from;
|
||||
if(son[now]) dfs2(son[now], from);
|
||||
for(int i : fri[now]) {
|
||||
if(i == fa[now] || i == son[now]) continue;
|
||||
dfs2(i, i);
|
||||
}
|
||||
}
|
||||
int lca(int a, int b) {
|
||||
while(top[a] != top[b]) {
|
||||
if(dep[top[a]] < dep[top[b]]) swap(a, b);
|
||||
a = fa[top[a]];
|
||||
}
|
||||
if(dep[a] < dep[b]) swap(a, b);
|
||||
return b;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d%d", &n, &q);
|
||||
for(int i = 1, u, v; i < n; ++i) {
|
||||
scanf("%d%d", &u, &v);
|
||||
fri[u].push_back(v);
|
||||
fri[v].push_back(u);
|
||||
}
|
||||
dfs1(1, 0);
|
||||
dfs2(1, 1);
|
||||
while(q--) {
|
||||
int a, b, c, d;
|
||||
scanf("%d%d%d%d", &a, &b, &c, &d);
|
||||
int lca1 = lca(a, b);
|
||||
int lca2 = lca(c, d);
|
||||
// lca1 在 [c, d] 上或 lca2 在 [a, b] 上
|
||||
if(dep[lca2] >= dep[lca1]) {
|
||||
if(lca(a, lca2) == lca2 || lca(b, lca2) == lca2) {
|
||||
printf("Y\n");
|
||||
} else {
|
||||
printf("N\n");
|
||||
}
|
||||
} else {
|
||||
if(lca(c, lca1) == lca1 || lca(d, lca1) == lca1) {
|
||||
printf("Y\n");
|
||||
} else {
|
||||
printf("N\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
- deep[x]>=deep[LCA(s,t)]
|
||||
|
||||
- LCA(s,x)=x或LCA(t,x)=x;
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,60 @@
|
||||
# P3398 仓鼠找 sugar
|
||||
|
||||
## 题目描述
|
||||
|
||||
小仓鼠的和他的基(mei)友(zi)sugar 住在地下洞穴中,每个节点的编号为 $1\sim n$。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室($a$)到餐厅($b$),而他的基友同时要从他的卧室($c$)到图书馆($d$)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?
|
||||
|
||||
|
||||
小仓鼠那么弱,还要天天被 zzq 大爷虐,请你快来救救他吧!
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行两个正整数 $n$ 和 $q$,表示这棵树节点的个数和询问的个数。
|
||||
|
||||
接下来 $n-1$ 行,每行两个正整数 $u$ 和 $v$,表示节点 $u$ 到节点 $v$ 之间有一条边。
|
||||
|
||||
接下来 $q$ 行,每行四个正整数 $a$、$b$、$c$ 和 $d$,表示节点编号,也就是一次询问,其意义如上。
|
||||
|
||||
## 输出格式
|
||||
|
||||
对于每个询问,如果有公共点,输出大写字母 `Y`;否则输出`N`。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5 5
|
||||
2 5
|
||||
4 2
|
||||
1 3
|
||||
1 4
|
||||
5 1 5 1
|
||||
2 2 1 4
|
||||
4 1 3 4
|
||||
3 1 1 5
|
||||
3 5 1 4
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
Y
|
||||
N
|
||||
Y
|
||||
Y
|
||||
Y
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
**本题时限 1s,内存限制 128M,因新评测机速度较为接近 NOIP 评测机速度,请注意常数问题带来的影响。**
|
||||
|
||||
|
||||
$20\%$ 的数据 $n, q\le200$。
|
||||
|
||||
$40\%$ 的数据 $n, q\le 2\times10^3$。
|
||||
|
||||
$70\%$ 的数据 $n, q\le 5\times10^4$。
|
||||
|
||||
$100\%$ 的数据 $1\le n, q\le10^5$。
|
||||
@@ -0,0 +1,122 @@
|
||||
#include<bits/stdc++.h>
|
||||
const int mod = 201314;
|
||||
using namespace std;
|
||||
int n, m;
|
||||
vector<int> chi[50005];
|
||||
int fa[50005];
|
||||
int cnt[50005];
|
||||
int son[50005];
|
||||
int top[50005];
|
||||
int dep[50005];
|
||||
int dfn[50005];
|
||||
int nowdfn;
|
||||
pair<int, int> query[100005];
|
||||
struct SEG{
|
||||
int num[400005], lt[400005];
|
||||
void pu(int now) {num[now] = (1ll * num[now * 2] + num[now * 2 + 1]) % mod;}
|
||||
void pd(int now, int nl, int nr) {
|
||||
int nmid = (nl + nr) >> 1;
|
||||
num[now * 2] = (num[now * 2] + 1ll * (nmid - nl + 1) * lt[now]) % mod;
|
||||
num[now * 2 + 1] = (num[now * 2 + 1] + 1ll * (nr - nmid) * lt[now]) % mod;
|
||||
lt[now * 2] = (lt[now * 2] + lt[now]) % mod;
|
||||
lt[now * 2 + 1] = (lt[now * 2 + 1] + lt[now]) % mod;
|
||||
lt[now] = 0;
|
||||
}
|
||||
void add(int now, int nl, int nr, int l, int r, int nn) {
|
||||
if(nl > r || nr < l) return;
|
||||
if(l <= nl && nr <= r) {
|
||||
num[now] = (num[now] + 1ll * (nr - nl + 1) * nn) % mod;
|
||||
lt[now] = (lt[now] + 1ll * nn) % mod;
|
||||
return;
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
add(now * 2, nl, nmid, l, r, nn);
|
||||
add(now * 2 + 1, nmid + 1, nr, l, r, nn);
|
||||
pu(now);
|
||||
}
|
||||
int query(int now, int nl, int nr, int l, int r) {
|
||||
if(nl > r || nr < l) return 0;
|
||||
if(l <= nl && nr <= r) {
|
||||
return num[now];
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
pd(now, nl, nr);
|
||||
return (1ll * query(now * 2, nl, nmid, l, r) + query(now * 2 + 1, nmid + 1, nr, l, r)) % mod;
|
||||
}
|
||||
}seg;
|
||||
void dfs1(int now) {
|
||||
cnt[now] = 1;
|
||||
for(int i : chi[now]) {
|
||||
dep[i] = dep[now] + 1;
|
||||
dfs1(i);
|
||||
cnt[now] += cnt[i];
|
||||
if(cnt[son[now]] < cnt[i]) son[now] = i;
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from) {
|
||||
top[now] = from;
|
||||
dfn[now] = ++nowdfn;
|
||||
if(son[now]) dfs2(son[now], from);
|
||||
for(int i : chi[now]) {
|
||||
if(i == son[now]) continue;
|
||||
dfs2(i, i);
|
||||
}
|
||||
}
|
||||
void addpath(int a, int b = 1) {
|
||||
while(top[a] != top[b]) {
|
||||
if(dep[top[a]] < dep[top[b]]) swap(a, b);
|
||||
seg.add(1, 1, n, dfn[top[a]], dfn[a], 1);
|
||||
a = fa[top[a]];
|
||||
}
|
||||
if(dep[a] < dep[b]) swap(a, b);
|
||||
seg.add(1, 1, n, dfn[b], dfn[a], 1);
|
||||
}
|
||||
int querypath(int a, int b = 1) {
|
||||
int ans = 0;
|
||||
while(top[a] != top[b]) {
|
||||
if(dep[top[a]] < dep[top[b]]) swap(a, b);
|
||||
ans = (ans + 1ll * seg.query(1, 1, n, dfn[top[a]], dfn[a])) % mod;
|
||||
a = fa[top[a]];
|
||||
}
|
||||
if(dep[a] < dep[b]) swap(a, b);
|
||||
return (ans + 1ll * seg.query(1, 1, n, dfn[b], dfn[a])) % mod;
|
||||
}
|
||||
int sx[100005];
|
||||
int ans[100005];
|
||||
int main() {
|
||||
scanf("%d%d", &n, &m);
|
||||
for(int i = 2; i <= n; ++i) {
|
||||
scanf("%d", &fa[i]);
|
||||
fa[i]++;
|
||||
chi[fa[i]].push_back(i);
|
||||
}
|
||||
dfs1(1);
|
||||
dfs2(1, 1);
|
||||
for(int i = 1, l, r, z; i <= m; ++i) {
|
||||
scanf("%d%d%d", &l, &r, &z);
|
||||
l++, r++, z++;
|
||||
sx[i] = i;
|
||||
sx[i + m] = i + m;
|
||||
query[2 * i - 1] = {l - 1, z};
|
||||
query[2 * i] = {r, z};
|
||||
}
|
||||
sort(sx + 1, sx + 2 * m + 1, [](int x, int y){return query[x] < query[y];});
|
||||
int cur = 0;
|
||||
for(int i = 1; i <= 2 * m; ++i) {
|
||||
int u = query[sx[i]].first;
|
||||
int w = query[sx[i]].second;
|
||||
while(cur < u) {
|
||||
++cur;
|
||||
addpath(cur);
|
||||
}
|
||||
ans[sx[i]] = querypath(w);
|
||||
}
|
||||
for(int i = 1; i <= m; ++i) {
|
||||
printf("%d\n", (ans[2 * i] - ans[2 * i - 1] + mod) % mod);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
从根到 [l, r] 中每个点的路径上的点均 + 1,最否求 z 到根的路径权值和
|
||||
*/
|
||||
@@ -0,0 +1,54 @@
|
||||
# P4211 [LNOI2014] LCA
|
||||
|
||||
## 题目描述
|
||||
|
||||
给出一个 $n$ 个节点的有根树(编号为 $0$ 到 $n-1$,根节点为 $0$)。
|
||||
|
||||
一个点的深度定义为这个节点到根的距离 $+1$。
|
||||
|
||||
设 $dep[i]$ 表示点 $i$ 的深度,$\operatorname{LCA}(i, j)$ 表示 $i$ 与 $j$ 的最近公共祖先。
|
||||
|
||||
有 $m$ 次询问,每次询问给出 $l, r, z$,求 $\sum_{i=l}^r dep[\operatorname{LCA}(i,z)]$ 。
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行 $2$ 个整数,$n, m$。
|
||||
|
||||
接下来 $n-1$ 行,分别表示点 $1$ 到点 $n-1$ 的父节点编号。
|
||||
|
||||
接下来 $m$ 行,每行 $3$ 个整数,$l, r, z$。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出 $m$ 行,每行表示一个询问的答案。每个答案对 $201314$ 取模输出。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5 2
|
||||
0
|
||||
0
|
||||
1
|
||||
1
|
||||
1 4 3
|
||||
1 4 2
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
8
|
||||
5
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
### 数据范围及约定
|
||||
|
||||
- 对于 $20\%$ 的数据,$n\le 10000,m\le 10000$;
|
||||
- 对于 $40\%$ 的数据,$n\le 20000,m\le 20000$;
|
||||
- 对于 $60\%$ 的数据,$n\le 30000,m\le 30000$;
|
||||
- 对于 $80\%$ 的数据,$n\le 40000,m\le 40000$;
|
||||
- 对于 $100\%$ 的数据,$1\le n\le 50000,1\le m\le 50000$。
|
||||
@@ -0,0 +1,60 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n, m;
|
||||
vector<int> fri[500005];
|
||||
int fa[500005];
|
||||
int dep[500005];
|
||||
int top[500005];
|
||||
int son[500005];
|
||||
int cnt[500005];
|
||||
void dfs1(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
for(int i : fri[now]) {
|
||||
if(i == from) continue;
|
||||
fa[i] = now;
|
||||
dep[i] = dep[now] + 1;
|
||||
dfs1(i, now);
|
||||
cnt[now] += cnt[i];
|
||||
if(cnt[son[now]] < cnt[i]) son[now] = i;
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from) {
|
||||
top[now] = from;
|
||||
if(son[now]) dfs2(son[now], from);
|
||||
for(int i : fri[now]) {
|
||||
if(i == fa[now] || i == son[now]) continue;
|
||||
dfs2(i, i);
|
||||
}
|
||||
}
|
||||
int lca(int a, int b) {
|
||||
while(top[a] != top[b]) {
|
||||
if(dep[top[a]] < dep[top[b]]) swap(a, b);
|
||||
a = fa[top[a]];
|
||||
}
|
||||
if(dep[a] < dep[b]) swap(a, b);
|
||||
return b;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d%d", &n, &m);
|
||||
for(int i = 1, u, v; i < n; ++i) {
|
||||
scanf("%d%d", &u, &v);
|
||||
fri[u].push_back(v);
|
||||
fri[v].push_back(u);
|
||||
}
|
||||
dfs1(1, 0);
|
||||
dfs2(1, 1);
|
||||
while(m--) {
|
||||
int x, y, z;
|
||||
scanf("%d%d%d", &x, &y, &z);
|
||||
int l1 = lca(x, y), l2 = lca(x, z), l3 = lca(y, z);
|
||||
int mind = min({dep[l1], dep[l2], dep[l3]});
|
||||
int maxd = max({dep[l1], dep[l2], dep[l3]});
|
||||
if(l1 == l2)
|
||||
printf("%d %d\n", l3, dep[x] + dep[y] + dep[z] - 2 * mind - maxd);
|
||||
else if(l1 == l3)
|
||||
printf("%d %d\n", l2, dep[x] + dep[y] + dep[z] - 2 * mind - maxd);
|
||||
else
|
||||
printf("%d %d\n", l1, dep[x] + dep[y] + dep[z] - 2 * mind - maxd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# P4281 [AHOI2008] 紧急集合 / 聚会
|
||||
|
||||
## 题目描述
|
||||
|
||||
欢乐岛上有个非常好玩的游戏,叫做“紧急集合”。在岛上分散有 $n$ 个等待点,有 $n-1$ 条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币。
|
||||
|
||||
参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费)、地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系)。当集合号吹响后,每组成员之间迅速联系,了解到自己组所有成员所在的等待点后,迅速在 $n$ 个等待点中确定一个集结点,组内所有成员将在该集合点集合,集合所用花费最少的组将是游戏的赢家。
|
||||
|
||||
小可可和他的朋友邀请你一起参加这个游戏,由你来选择集合点,聪明的你能够完成这个任务,帮助小可可赢得游戏吗?
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行两个正整数 $n$ 和 $m$,分别表示等待点的个数(等待点也从 $1$ 到 $n$ 进行编号)和获奖所需要完成集合的次数。
|
||||
|
||||
随后 $n-1$ 行,每行两个正整数 $a,b$,表示编号为 $a$ 和编号为 $b$ 的等待点之间有一条路。
|
||||
|
||||
随后 $m$ 行,每行用三个正整数 $x,y,z$,表示某次集合前小可可、小可可的朋友以及你所在等待点的编号。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出共 $m$ 行,每行两个用空格隔开的整数 $p,c$。其中第 $i$ 行表示第 $i$ 次集合点选择在编号为 $p$ 的等待点,集合总共的花费是 $c$ 个游戏币。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
6 4
|
||||
1 2
|
||||
2 3
|
||||
2 4
|
||||
4 5
|
||||
5 6
|
||||
4 5 6
|
||||
6 3 1
|
||||
2 4 4
|
||||
6 6 6
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
5 2
|
||||
2 5
|
||||
4 1
|
||||
6 0
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
对于 $40\%$ 的数据,$n\leq2\times10^3$,$m\leq2\times 10^3$。
|
||||
|
||||
对于 $100\%$ 的数据,$1\leq x,y,z\leq n\leq 5\times10^5$,$1\leq m\leq 5\times 10^5$。
|
||||
@@ -0,0 +1,85 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int mod = 998244353;
|
||||
int n, m, k;
|
||||
int up;
|
||||
vector<int> fri[300005];
|
||||
int fa[3000005];
|
||||
int cnt[300005];
|
||||
int son[300005];
|
||||
int dfn[300005];
|
||||
int rev[300005];
|
||||
int top[300005];
|
||||
int dep[300005];
|
||||
int nowdfn;
|
||||
struct SEG{
|
||||
int num[51][1200005];
|
||||
void init(int now, int nl, int nr) {
|
||||
if(nl == nr) {
|
||||
num[0][now] = 1;
|
||||
for(int i = 1; i <= 50; ++i)
|
||||
num[i][now] = (1ll * num[i - 1][now] * dep[rev[nl]]) % mod;
|
||||
return;
|
||||
}
|
||||
int nmid = (nl + nr) >> 1;
|
||||
init(now * 2, nl, nmid);
|
||||
init(now * 2 + 1, nmid + 1, nr);
|
||||
for(int i = 1; i <= 50; ++i) num[i][now] = (1ll * num[i][now * 2] + num[i][now * 2 + 1]) % mod;
|
||||
}
|
||||
int query(int now, int nl, int nr, int l, int r) {
|
||||
if(nl > r || nr < l) return 0;
|
||||
if(l <= nl && nr <= r) return num[k][now];
|
||||
int nmid = (nl + nr) >> 1;
|
||||
return (1ll * query(now * 2, nl, nmid, l, r) + query(now * 2 + 1, nmid + 1, nr, l, r)) % mod;
|
||||
}
|
||||
}seg;
|
||||
void dfs1(int now, int from) {
|
||||
cnt[now] = 1;
|
||||
for(int i : fri[now]) {
|
||||
if(i == from) continue;
|
||||
fa[i] = now;
|
||||
dep[i] = dep[now] + 1;
|
||||
dfs1(i, now);
|
||||
cnt[now] += cnt[i];
|
||||
if(cnt[i] > cnt[son[now]]) son[now] = i;
|
||||
}
|
||||
}
|
||||
void dfs2(int now, int from) {
|
||||
dfn[now] = ++nowdfn;
|
||||
rev[nowdfn] = now;
|
||||
top[now] = from;
|
||||
if(son[now]) dfs2(son[now], from);
|
||||
for(int i : fri[now]) {
|
||||
if(i == fa[now] || i == son[now]) continue;
|
||||
dfs2(i, i);
|
||||
}
|
||||
}
|
||||
int query(int a, int b) {
|
||||
int ans = 0;
|
||||
while(top[a] != top[b]) {
|
||||
if(dep[top[a]] < dep[top[b]]) swap(a, b);
|
||||
ans = (ans + 1ll * seg.query(1, 1, n, dfn[top[a]], dfn[a])) % mod;
|
||||
a = fa[top[a]];
|
||||
}
|
||||
if(dep[a] < dep[b]) swap(a, b);
|
||||
ans = (ans + 1ll * seg.query(1, 1, n, dfn[b], dfn[a])) % mod;
|
||||
return ans;
|
||||
}
|
||||
int main() {
|
||||
scanf("%d", &n);
|
||||
for(int i = 1, u, v; i < n; ++i) {
|
||||
scanf("%d%d", &u, &v);
|
||||
fri[u].push_back(v);
|
||||
fri[v].push_back(u);
|
||||
}
|
||||
dfs1(1, 0);
|
||||
dfs2(1, 1);
|
||||
seg.init(1, 1, n);
|
||||
scanf("%d", &m);
|
||||
for(up = 1; up <= m; ++up) {
|
||||
int i, j;
|
||||
scanf("%d%d%d", &i, &j, &k);
|
||||
printf("%d\n", query(i, j));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
# P4427 [BJOI2018] 求和
|
||||
|
||||
## 题目描述
|
||||
|
||||
master 对树上的求和非常感兴趣。他生成了一棵有根树,并且希望多次询问这棵树上一段路径上所有节点深度的 $k$ 次方和,而且每次的 $k$ 可能是不同的。此处节点深度的定义是这个节点到根的路径上的边数。他把这个问题交给了 pupil,但 pupil 并不会这么复杂的操作,你能帮他解决吗?
|
||||
|
||||
## 输入格式
|
||||
|
||||
第一行包含一个正整数 $n$,表示树的节点数。
|
||||
|
||||
之后 $n-1$ 行每行两个空格隔开的正整数 $i, j$,表示树上的一条连接点 $i$ 和点 $j$ 的边。
|
||||
|
||||
之后一行一个正整数 $m$,表示询问的数量。
|
||||
|
||||
之后每行三个空格隔开的正整数 $i, j, k$,表示询问从点 $i$ 到点 $j$ 的路径上所有节点深度的 $k$ 次方和。由于这个结果可能非常大,输出其对 $998244353$ 取模的结果。
|
||||
|
||||
树的节点从 $1$ 开始标号,其中 $1$ 号节点为树的根。
|
||||
|
||||
## 输出格式
|
||||
|
||||
对于每组数据输出一行一个正整数表示取模后的结果。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
5
|
||||
1 2
|
||||
1 3
|
||||
2 4
|
||||
2 5
|
||||
2
|
||||
1 4 5
|
||||
5 4 45
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
33
|
||||
503245989
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
### 样例解释
|
||||
|
||||
以下用 $d (i)$ 表示第 $i$ 个节点的深度。
|
||||
|
||||
对于样例中的树,有 $d (1) = 0, d (2) = 1, d (3) = 1, d (4) = 2, d (5) = 2$。
|
||||
|
||||
因此第一个询问答案为 $(2^5 + 1^5 + 0^5) \bmod 998244353 = 33$,第二个询问答案为$(2^{45} + 1^{45} + 2^{45}) \bmod 998244353 = 503245989$。
|
||||
|
||||
### 数据范围
|
||||
|
||||
对于 $30\%$ 的数据,$1 \leq n,m \leq 100$。
|
||||
|
||||
对于 $60\%$ 的数据,$1 \leq n,m \leq 1000$。
|
||||
|
||||
对于 $100\%$ 的数据,$1 \leq n,m \leq 300000$,$1 \leq k \leq 50$。
|
||||
|
||||
另外存在 5 个不计分的 hack 数据。
|
||||
|
||||
### 提示
|
||||
|
||||
数据规模较大,请注意使用较快速的输入输出方式。
|
||||
@@ -0,0 +1,33 @@
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
long long a;
|
||||
int minans = INT_MAX;
|
||||
int n;
|
||||
void dfs(int now, int pre_k, long long now_a) {
|
||||
if(now > 6 || now >= minans) {
|
||||
return;
|
||||
}
|
||||
if(now_a == (1ll << n) - 1) {
|
||||
minans = min(minans, now);
|
||||
}
|
||||
for(int k = pre_k; k <= n; ++k) {
|
||||
long long new_a = now_a | (now_a >> k);
|
||||
if(new_a > now_a) dfs(now + 1, k, new_a);
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
char s[45];
|
||||
scanf("%s", s + 1);
|
||||
if(s[1] == '0') {
|
||||
printf("-1\n");
|
||||
return 0;
|
||||
}
|
||||
n = strlen(s + 1);
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
a *= 2;
|
||||
if(s[i] == '1') a += 1;
|
||||
}
|
||||
dfs(0, 1, a);
|
||||
printf("%d\n", minans);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
# P7458 [CERC2018] Clockwork ||ange
|
||||
|
||||
## 题目描述
|
||||
|
||||
**译自[ [CERC2018]](https://contest.felk.cvut.cz/18cerc/) [Clockwork ||ange](https://contest.felk.cvut.cz/18cerc/solved/clockwork.pdf)**
|
||||
|
||||
据百度百科,兔是哺乳类兔形目兔科下属所有的属的总称。毋庸置疑的是,这段文字不是无聊的,因为它们是原始的,并且组织良好。我们农场的兔子生活在有保护的畜栏里,畜栏的边界装饰有精美的花卉装饰品。畜栏里生长着数十个可爱的橙色胡萝卜。兔子繁殖很快(这很正常,每年都有成千上万的兔子出生),我们的导师希望不费力地把它们安置在畜栏里。
|
||||
|
||||
畜栏规则地形成一排。在第一个繁殖季开始时,一些畜栏里可能没有兔子。每个繁殖季结束时,都会进行一次精心策划过的兔子搬迁。搬迁遵循一条简单的公式,这个公式取决于一个正整数 $K$,不同的繁殖季 $K$ 值不一定相同。对于所有畜栏,搬迁工作同时进行。在每个畜栏中,大约有一半的兔子被移到这个畜栏右边第 $K$ 个畜栏里。目标畜栏里原来有没有兔子都没有关系。
|
||||
|
||||
如果畜栏离这一排最后一个畜栏太近(即离最后一个畜栏的距离小于 $K$ ),那么这个畜栏中的所有兔子都留在原畜栏,不会进行搬迁。
|
||||
|
||||
每个畜栏都可以容纳无限只兔子,并且非空的畜栏中总有足够多能够成功繁殖的兔子。
|
||||
|
||||
给定第一个繁殖季开始时畜栏被占用的情况。请求出使得所有畜栏中都有兔子的最少搬迁次数。
|
||||
|
||||
## 输入格式
|
||||
|
||||
输入仅有一行,包含一个长度为 $b$ 的字符串,每个字符表示一个畜栏。字符只有 $0$(空畜栏)和 $1$(有兔子的畜栏)两种。第一个字符表示这一排的第一个畜栏。
|
||||
|
||||
## 输出格式
|
||||
|
||||
输出使得所有畜栏中都有兔子的最少搬迁次数。如果没有任何一种搬迁方案使得每个畜栏中都有兔子,输出 $-1$。
|
||||
|
||||
## 输入输出样例 #1
|
||||
|
||||
### 输入 #1
|
||||
|
||||
```
|
||||
1010
|
||||
```
|
||||
|
||||
### 输出 #1
|
||||
|
||||
```
|
||||
1
|
||||
```
|
||||
|
||||
## 输入输出样例 #2
|
||||
|
||||
### 输入 #2
|
||||
|
||||
```
|
||||
100110000
|
||||
```
|
||||
|
||||
### 输出 #2
|
||||
|
||||
```
|
||||
3
|
||||
```
|
||||
|
||||
## 说明/提示
|
||||
|
||||
$1≤b≤40$
|
||||
@@ -0,0 +1,70 @@
|
||||
# CSPS 2026 游记
|
||||
|
||||
华二紫竹,$2026-10-31T14:30+08:00 \sim 2026-10-31T18:30+08:00$。
|
||||
|
||||
## timeline (git commit history):
|
||||
|
||||
- 14:39 init (带 diff.sh)
|
||||
- 14:58 T1 45 pts
|
||||
- 15:26 T1 100 pts
|
||||
- 15:34 为 T1 写了 gen
|
||||
- 16:04 T2 20pts(实际 36 pts)
|
||||
- 16:15 T2 60 pts(实际 68 pts)
|
||||
- 16:19 T2 开 long long
|
||||
- 16:22 T1 对拍发现有一个变量没开 long long(感谢 diff.sh)
|
||||
- 16:50 为 T2 写了 gen(然而 gen 的数据并不保证图连通 这个考场上导致好多次误判)
|
||||
- 17:07 因为 T2 gen 的构造的数据问题导致不必要的 long long 和特判
|
||||
- 17:59 依旧卡 T2,T3 T4 毫无推进
|
||||
- (约)18:20 发现 T2 并无问题,尝试写 T3 T4 暴力,然而时间不够
|
||||
|
||||
## T1
|
||||
|
||||
最开始以为答案是关于最终相等的数单调的,想写二分,发现第二个样例证伪了这一结论。发现最终相同的数一定是 $a_i (i \in [1, n])$。
|
||||
|
||||
先写了个 [45pts 的暴力](https://git.vblg.top/hanyixuanten/csps2026/src/commit/bf08016dee210d518b187b7730a4f8f27ae47f24/crystal/crystal.cpp)。此时考试已开始 28 min。
|
||||
|
||||
考虑到使用二分 + 前缀和优化[寻找 ans 的过程](https://git.vblg.top/hanyixuanten/csps2026/src/commit/bf08016dee210d518b187b7730a4f8f27ae47f24/crystal/crystal.cpp#L12-L13)。但是因为二分出来的答案一直多 1 或少 1,就出现了[这几行代码(笑哭)](https://git.vblg.top/hanyixuanten/csps2026/src/commit/8b21377d1fa3208ef8d27b7592e91d1dbf8a40fc/crystal/crystal.cpp#L22-L23)。
|
||||
|
||||
然而,最开始的时候 [checkb 函数的 now 没开 long long](https://git.vblg.top/hanyixuanten/csps2026/src/commit/8b21377d1fa3208ef8d27b7592e91d1dbf8a40fc/crystal/crystal.cpp#L7),差点 100->65,diff.sh 立大功。
|
||||
|
||||
附 [gen.cpp](https://git.vblg.top/hanyixuanten/csps2026/src/commit/c9a42541c404d2b6395e49b9c35e4eb71109327b/crystal/gen.cpp)。
|
||||
|
||||
## T2
|
||||
|
||||
其实考试开始 34 min 就想出了[“500 条线路各视为图上的一个点,分别和地铁站连线”](https://git.vblg.top/hanyixuanten/csps2026/src/commit/64eda003fc35794e1805274785a058db89a21eeb/subway/subway.cpp#L49),但是由于无负边权,自然的想到了 dij,后续又加入了预处理优化,16:15 写完后发现并不能通过最后两个大样例(3s)。然而并没有想到 $O(n^3)$ 的 Floyd 在这种情况下更快。(写这篇记录的时候还没有正式出成绩,若 CCF 的评测机发力则可能多点分。)
|
||||
|
||||
附 [gen.cpp](https://git.vblg.top/hanyixuanten/csps2026/src/commit/e4991898d0b1585aa9d86a0737da057bd388de58/subway/gen.cpp)。注意这个 gen.cpp 生成的图不保证连通,所以如果代码输出了 inf 或是负数一般是图不连通导致,可忽略。
|
||||
|
||||
## T3 T4
|
||||
|
||||
由于死磕 T2 连暴力都没有写,血亏 20-60pts。
|
||||
|
||||
## 总结
|
||||
|
||||
1. 对拍、diff.sh 立大功。
|
||||
2. 由于随机数只会用 time(0) 作为种子,导致对拍效率大大下降,连续拍了半个小时才发现 T1 的问题。
|
||||
3. 过度的死磕 T2 导致 T3 T4 暴力没写。
|
||||
4. 对算法复杂度 (dij) 有错误估测,忽视冷门算法 (Floyd),导致 T2 100 -> 68。
|
||||
|
||||
附 diff.sh(linux,注意对拍代码均无需开文件读写):
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
g++ sol1.cpp -o sol1 -O2 -std=c++14 -static
|
||||
g++ sol2.cpp -o sol2 -O2 -std=c++14 -static
|
||||
g++ gen.cpp -o gen -O3 -std=c++14 -static
|
||||
for i in {1..10000}; do
|
||||
gen > in
|
||||
sol1 < in > a
|
||||
sol2 < in > b
|
||||
if ! diff -q a b > /dev/null; then
|
||||
echo wa
|
||||
cp in wa.in
|
||||
cp a wa1.out
|
||||
cp b wa2.out
|
||||
break
|
||||
fi
|
||||
echo success $i
|
||||
done
|
||||
```
|
||||
@@ -0,0 +1,106 @@
|
||||
# CF1380D Berserk And Fireball 题解
|
||||
|
||||
> 考场上没有看见 $a_i$ 两两不同,卡了半天。
|
||||
|
||||
下文用“$k$ 删除”代表“火球术”,用“单点删除”代表“狂暴术”。
|
||||
|
||||
先判断是运行一次 $k$ 删除更优或者运行 $k$ 次单点删除更优。
|
||||
|
||||
由于 $a_i$ 两两不同,显然可以使用一个 `map` 保存 $a_i$ 所在的位置 $index_{a_i}$。
|
||||
|
||||
对于每对 $b_{i - 1}, b_i$,得到区间 $[index_{b_{i - 1}}, index_{b_i}]$ (其中 $index_0 = 0$),设 $len = index_{b_i} - index_{b_{i - 1}} - 1$。然后分类讨论:
|
||||
|
||||
- 若 $k$ 删除更优,可以先运行 $len \% k$ 次单点删除,然后运行 $\lfloor \frac{len}{k} \rfloor$ 次 $k$ 删除。
|
||||
- 若单点删除更优:
|
||||
- 若区间内有数 $a_i > \max{(a_{index_{b_{i - 1}}}, a_{index_{b_i}})}$,则必须运行一次 $k$ 删除来移除这个数,因此先运行 $len - k$ 次单点删除,最后运行一次 $k$ 删除。
|
||||
- 否则,可以直接运行 $len$ 次单点删除。
|
||||
|
||||
由此我们就可以得到无解条件:区间内有大于两边的数且区间长度 $< k$,或 $index_{b_{i - 1}} > index_{b_i}$。
|
||||
|
||||
注意不要忘了处理最后一个区间。
|
||||
|
||||
::::success[code]
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int n, m, k;
|
||||
long long x, y;
|
||||
int a[200005];
|
||||
int b, preb;
|
||||
int pos[200005];
|
||||
bool k_is_better;
|
||||
vector<int> mor;
|
||||
long long del(int pre, int todo)
|
||||
{
|
||||
if (todo <= pre)
|
||||
return -1;
|
||||
if (todo == pre + 1)
|
||||
return 0;
|
||||
mor.clear();
|
||||
for (int j = pre + 1; j <= todo - 1; ++j)
|
||||
if (a[j] > max(a[todo], a[pre]))
|
||||
mor.push_back(j);
|
||||
if (!mor.empty() && (todo - pre - 1) < k) // 如果有大数且长度不足以运行一次 k 则不存在
|
||||
return -1;
|
||||
if (k_is_better)
|
||||
{
|
||||
return ((todo - pre - 1) % k) * y + ((todo - pre - 1) / k) * x; // 先用 y 移除多余的数,最后用多个 k 直接删完
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mor.empty())
|
||||
return (todo - pre - 1 - k) * y + x; // 用一次k清除最大数,其余用y
|
||||
else
|
||||
return (todo - pre - 1) * y; // 全部用y
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
scanf("%d%d%lld%d%lld", &n, &m, &x, &k, &y);
|
||||
k_is_better = x < (k * y);
|
||||
for (int i = 1; i <= n; ++i)
|
||||
{
|
||||
scanf("%d", &a[i]);
|
||||
pos[a[i]] = i;
|
||||
}
|
||||
long long ans = 0;
|
||||
for (int i = 1; i <= m; ++i)
|
||||
{
|
||||
scanf("%d", &b);
|
||||
int todo = pos[b], pre = 0;
|
||||
if (i != 1)
|
||||
pre = pos[preb];
|
||||
long long d = del(pre, todo);
|
||||
if (d == -1ll)
|
||||
{
|
||||
printf("-1\n");
|
||||
return 0;
|
||||
}
|
||||
ans += d;
|
||||
preb = b;
|
||||
}
|
||||
long long d = del(pos[b], n + 1);
|
||||
if (d == -1ll)
|
||||
{
|
||||
printf("-1\n");
|
||||
return 0;
|
||||
}
|
||||
printf("%lld\n", ans + d);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
若 k 删除更优,先删到能被 k 整除的长度,则先 k 删除,最后运行多次 k 删除
|
||||
len % k
|
||||
若 1 删除更优,先用 k 删除删去大于两边的,最后用 1 删除
|
||||
7 2
|
||||
3 3 1
|
||||
5 7 0 3 1 6 4
|
||||
5 4
|
||||
|
||||
输出 5
|
||||
*/
|
||||
```
|
||||
|
||||
::::
|
||||
+2
-2
@@ -2,6 +2,6 @@
|
||||
|
||||
题意可转化为有一棵树,每个节点有权值,一个边两端的点不能同时去,同时 $S, T$ 也不能同时取(断开环上的两个点)。
|
||||
|
||||
因此可转化两次为[P1352 没有上司的舞会](https://www.luogu.com.cn/problem/P1352#),设 $f_{i, 01}$ 以 $i$ 为根的子树,是否选择本节点的收益,只需[以 $S$ 为根时令 $f_{T, 1} = -\inf$,以 $T$ 为根时令 $f_{S, 1} = -\inf$ 即可。](../P1453.cpp#L17-19)
|
||||
因此可转化两次为[P1352 没有上司的舞会](https://www.luogu.com.cn/problem/P1352#),设 $f_{i, 01}$ 以 $i$ 为根的子树,是否选择本节点的收益,只需[以 $S$ 为根时令 $f_{T, 1} = -\inf$,以 $T$ 为根时令 $f_{S, 1} = -\inf$ 即可。](../P1453.cpp#L17-L18)
|
||||
|
||||
[code](../P1453.cpp)
|
||||
[code](../P1453.cpp)
|
||||
+1
-1
@@ -6,6 +6,6 @@
|
||||
|
||||
本题与[P1453](../P1453.md)的区别是形成的不只是一个树+断边,而是一个森林+断边。
|
||||
|
||||
只需要将 [P1453 的并查集](../P1453.cpp#L35-42)改为[保存 $S, T$ vector](../P2607.cpp#L33-40),随后对于每个树+断边仿照 P1453 的实现即可
|
||||
只需要将 [P1453 的并查集](../P1453.cpp#L35-L41)改为[保存 $S, T$ vector](../P2607.cpp#L33-L39),随后对于每个树+断边仿照 P1453 的实现即可
|
||||
|
||||
[code](../P2607.cpp)
|
||||
@@ -0,0 +1,16 @@
|
||||
# P3384 【模板】重链剖分 / 树链剖分 题解
|
||||
|
||||
重链剖分模板。习惯用线段树(也可以双 BIT)。
|
||||
|
||||
其中:
|
||||
|
||||
- [L13-48](../P3384.cpp#L13-L48) 为维护区间和的线段树。
|
||||
- [L49-59](../P3384.cpp#L49-L59) 为 dfs1,处理 $dep, cnt, fa, son$。
|
||||
- [L60-71](../P3384.cpp#L60-L71) 为 dfs2,处理 $dfn, top$。
|
||||
- [L72-80](../P3384.cpp#L72-L80) 为路径加,上跳即可。
|
||||
- [L81-90](../P3384.cpp#L81-L90) 为路径查询,与修改是类似的。
|
||||
- [L91-96](../P3384.cpp#L91-L96) 为子树修改与查询,由于子树的 $dfn$ 序列是连续的,直接在线段树上修改即可。
|
||||
|
||||
接下来建议用树链剖分解决一些[简单题](https://www.luogu.com.cn/problem/list?type=luogu&page=1&tag=228&orderBy=difficulty&order=asc)。
|
||||
|
||||
[code](../P3384.cpp)
|
||||
@@ -0,0 +1,17 @@
|
||||
# P4211 [LNOI2014] LCA 题解
|
||||
|
||||
给定一棵树,对于每个给定的 $l, r, z$,求:
|
||||
|
||||
$$\sum_{i = l}^r dep[\operatorname{LCA}(i, z)]$$
|
||||
|
||||
考虑转化。$dep[\operatorname{LCA}(x, y)]$ 表示从根节点到 $\operatorname{LCA}(x, y)$ 节点经过的节点数,其相当于对于根节点到 $x$ 的路径上每个点都 $+ 1$,求从根节点到 $y$ 的路径上所有节点的权值和。
|
||||
|
||||
因此,考虑使用树链剖分,对于每次操作,对 $root \rightarrow i, i \in [l, r]$ 的路径上每个点权值 $+ 1$,并求 $root \rightarrow z$ 的路径上所有节点的权值和。
|
||||
|
||||
然后,很自然地,可以分别计算 $l - 1, r$ 时的答案,并维护差分求解。
|
||||
|
||||
但是,若是每次操作都清除线段树,显然有点浪费。考虑将询问离线为 $2 \times m$ 次 $[1, l - 1 \text{or } r]$ 时的查询,按照右端点排序求解。
|
||||
|
||||
总时间复杂度 $\operatorname O(n \log^2 n)$
|
||||
|
||||
[code](../P4211.cpp)
|
||||
@@ -0,0 +1,77 @@
|
||||
# P7458 [CERC2018] Clockwork ||ange 题解
|
||||
|
||||
## 二进制表示
|
||||
|
||||
我们只关心每个畜栏是否非空,因此可以用一个二进制数表示整个畜栏状态。
|
||||
|
||||
一次搬迁选择正整数 $K$,在二进制表示中,“右边第 $K$ 个畜栏”正好对应右移 $K$ 位。因此一次操作可以写成 $newa = nowa \mid (nowa \gg K)$。其中:
|
||||
|
||||
- $nowa$ 保留原来的非空畜栏。
|
||||
- $nowa \gg K$ 把兔子移动到右边第 $K$ 个畜栏。
|
||||
- 按位或表示合并新旧状态。
|
||||
|
||||
如果某个畜栏离最后一个畜栏太近,右移后越界,越界部分自然消失;而原畜栏仍然保留,所以正好符合题目“太靠右则全部留在原畜栏”的规则。
|
||||
|
||||
## DFS 搜索
|
||||
|
||||
设当前状态为 $nowa$,已经进行了 $now$ 次搬迁,上一次选择的 $K$ 为 $pre_k$。
|
||||
|
||||
由于每次操作都是“并上右移后的结果”,操作顺序实际上可以交换。因此我们可以限制选择的 $K$ 非降,避免重复枚举同一种操作序列。
|
||||
|
||||
其中 $newa > nowa$ 用来剪掉没有产生任何新非空畜栏的操作。因为所有可达状态都包含初始状态 $a$,所以 $newa > nowa$ 等价于“至少新增了一个初始为空的畜栏”。如果一次操作没有新增任何畜栏,它不会帮助达到目标,可以跳过。
|
||||
|
||||
如果:
|
||||
|
||||
```cpp
|
||||
now_a == (1ll << n) - 1
|
||||
```
|
||||
|
||||
说明所有 $n$ 个畜栏都非空,更新答案。
|
||||
|
||||
## 为什么最多只需要 6 次
|
||||
|
||||
如果第一个畜栏有兔子,那么可以依次选择 $K = 1, 2, 4, 8, 16, 32$。
|
||||
|
||||
不难发现,只要第一个畜栏有兔子,六次操作一定可以填满。
|
||||
|
||||
## 参考代码
|
||||
|
||||
::::success[code]
|
||||
|
||||
```cpp
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
long long a;
|
||||
int minans = INT_MAX;
|
||||
int n;
|
||||
void dfs(int now, int pre_k, long long now_a) {
|
||||
if(now > 6 || now >= minans) {
|
||||
return;
|
||||
}
|
||||
if(now_a == (1ll << n) - 1) {
|
||||
minans = min(minans, now);
|
||||
}
|
||||
for(int k = pre_k; k <= n; ++k) {
|
||||
long long new_a = now_a | (now_a >> k);
|
||||
if(new_a > now_a) dfs(now + 1, k, new_a);
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
char s[45];
|
||||
scanf("%s", s + 1);
|
||||
if(s[1] == '0') {
|
||||
printf("-1\n");
|
||||
return 0;
|
||||
}
|
||||
n = strlen(s + 1);
|
||||
for(int i = 1; i <= n; ++i) {
|
||||
a *= 2;
|
||||
if(s[i] == '1') a += 1;
|
||||
}
|
||||
dfs(0, 1, a);
|
||||
printf("%d\n", minans);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
::::
|
||||
Reference in new issue
Block a user