Codeforces Global Round 1
蒟蒻的再一次血崩
A. Parity
Description:
You are given an integer n ( n≥0) represented with k digits in base (radix) b. So,
n=a1⋅bk−1+a2⋅bk−2+…ak−1⋅b+ak.
For example, if b=17,k=3 and a=[11,15,7] then n=11⋅172+15⋅17+7=3179+255+7=3441.
Determine whether n is even or odd.
Input:
The first line contains two integers b and k ( 2≤b≤100, 1≤k≤105) — the base of the number and the number of digits.
The second line contains k integers a1,a2,…,ak ( 0≤ai<b) — the digits of n.
The representation of n contains no unnecessary leading zero. That is, a1 can be equal to 0 only if k=1.
Output
Print “even” if n is even, otherwise print “odd”.
You can print each letter in any case (upper or lower).
Sample Input:
13 3
3 2 7
Sample Output:
even
Sample Input:
10 9
1 2 3 4 5 6 7 8 9
Sample Output:
odd
Sample Input:
99 5
32 92 85 74 4
Sample Output:
odd
Sample Input:
2 2
1 0
Sample Output:
even
题目链接
根据奇偶相加为奇,奇奇、偶偶相加为偶依次判断即可
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int B, K;
int A[maxn];
bool Cur;
int main(int argc, char *argv[]) {
scanf("%d%d", &B, &K);
Cur = true;
for (int i = 1; i <= K; ++i) {
scanf("%d", &A[i]);
if (i == K && Cur && (A[i] & 1)) {
Cur = false;
continue;
}
if ((A[i] & 1) && (B & 1)) Cur = !Cur;
}
if (Cur) printf("even\n");
else printf("odd\n");
return 0;
}
B. Tape
Description:
You have a long stick, consisting of m segments enumerated from 1 to m. Each segment is 1 centimeter long. Sadly, some segments are broken and need to be repaired.
You have an infinitely long repair tape. You want to cut some pieces from the tape and use them to cover all of the broken segments. To be precise, a piece of tape of integer length t placed at some position s will cover segments s,s+1,…,s+t−1.
You are allowed to cover non-broken segments; it is also possible that some pieces of tape will overlap.
Time is money, so you want to cut at most k continuous pieces of tape to cover all the broken segments. What is the minimum total length of these pieces?
Input:
The first line contains three integers n, m and k ( 1≤n≤105, n≤m≤109, 1≤k≤n) — the number of broken segments, the length of the stick and the maximum number of pieces you can use.
The second line contains n integers b1,b2,…,bn ( 1≤bi≤m) — the positions of the broken segments. These integers are given in increasing order, that is, b1<b2<…<bn.
Output
Print the minimum total length of the pieces.
Sample Input:
4 100 2
20 30 75 80
Sample Output:
17
Sample Input:
5 100 3
1 2 4 60 87
Sample Output:
6
题目链接
差分计算每段长度,去掉最长的 k−1 段即可
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int N, M, K;
int B[maxn];
ll Seg[maxn];
ll Ans;
int main(int argc, char *argv[]) {
scanf("%d%d%d", &N, &M, &K);
if (N == 1) {
printf("1\n");
return 0;
}
for (int i = 0; i < N; ++i) scanf("%d", &B[i]);
for (int i = 1; i < N; ++i) Seg[i] = B[i] - B[i - 1];
sort(Seg + 1, Seg + N);
for (int i = 1; i < N - (K - 1); ++i) Ans += Seg[i];
printf("%lld\n", Ans + K);
return 0;
}
C. Meaningless Operations
Description:
Can the greatest common divisor and bitwise operations have anything in common? It is time to answer this question.
Suppose you are given a positive integer a. You want to choose some integer b from 1 to a−1 inclusive in such a way that the greatest common divisor (GCD) of integers a⊕b and a&b is as large as possible. In other words, you’d like to compute the following function:
f(a)=0<b<amaxgcd(a⊕b,a&b).
Here ⊕ denotes the bitwise XOR operation, and & denotes the bitwise AND operation.
The greatest common divisor of two integers x and y is the largest integer g such that both x and y are divided by g without remainder.
You are given q integers a1,a2,…,aq. For each of these integers compute the largest possible value of the greatest common divisor (when b is chosen optimally).
Input:
The first line contains an integer q ( 1≤q≤103) — the number of integers you need to compute the answer for.
After that q integers are given, one per line: a1,a2,…,aq ( 2≤ai≤225−1) — the integers you need to compute the answer for.
Output
For each integer, print the answer in the same order as the integers are given in input.
Sample Input:
3
2
3
5
Sample Output:
3
1
7
题目链接
观察易得若 n̸=2x−1 则其结果在二进制上与 n 等长且每一位均为 1
若 n=2x−1 则打表特判即可
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
ll N;
ll Len;
map<ll, ll> Mp;
int main(int argc, char *argv[]) {
Mp[3] = 1; Mp[7] = 1; Mp[15] = 5; Mp[31] = 1; Mp[63] = 21;
Mp[127] = 1; Mp[255] = 85; Mp[511] = 73; Mp[1023] = 341;
Mp[2047] = 89; Mp[4095] = 1365; Mp[8191] = 1; Mp[16383] = 5461;
Mp[32767] = 4681; Mp[65535] = 21845; Mp[131071] = 1;
Mp[262143] = 87381; Mp[524287] = 1; Mp[1048575] = 349525;
Mp[2097151] = 299593; Mp[4194303] = 1398101; Mp[8388607] = 178481;
Mp[16777215] = 5592405; Mp[33554431] = 1082401;
scanf("%d\n", &T);
for (int Case = 1; Case <= T; ++Case) {
scanf("%lld", &N);
Len = log2(N) + 1;
if (Mp[N]) printf("%lld\n", Mp[N]);
else printf("%lld\n", (1ll << Len) - 1);
}
return 0;
}
D. Jongmah
Description:
You are playing a game of Jongmah. You don’t need to know the rules to solve this problem. You have n tiles in your hand. Each tile has an integer between 1 and m written on it.
To win the game, you will need to form some number of triples. Each triple consists of three tiles, such that the numbers written on the tiles are either all the same or consecutive. For example, 7,7,7 is a valid triple, and so is 12,13,14, but 2,2,3 or 2,4,6 are not. You can only use the tiles in your hand to form triples. Each tile can be used in at most one triple.
To determine how close you are to the win, you want to know the maximum number of triples you can form from the tiles in your hand.
Input:
The first line contains two integers integer n and m ( 1≤n,m≤106) — the number of tiles in your hand and the number of tiles types.
The second line contains integers a1,a2,…,an ( 1≤ai≤m), where ai denotes the number written on the i-th tile.
Output
Print one integer: the maximum number of triples you can form.
Sample Input:
10 6
2 3 3 3 4 4 4 5 5 6
Sample Output:
3
Sample Input:
12 6
1 5 3 3 3 4 3 5 3 2 3 3
Sample Output:
3
Sample Input:
13 5
1 1 5 1 2 3 3 2 4 2 3 4 5
Sample Output:
4
题目链接
求一个数列中得数字可以组成多少连续或相同数字的三元组
构造三元组时不存在 3 组或以上个 [x−1,x,x+1] ,因为若存在则我们可以拆分为 [x−1,x−1.x−1],[x,x,x],[x+1,x+1,x+1]
考虑动态规划, dp[a][i][j] 表示 [1,a] 中有 i 个形如 [a−1,a,a+1] 的三元组和 j 个形如 [a,a+1,a+2] 的三元组
枚举 k 为形如 [a+1,a+2,a+3] 的三元组,把剩下的 a+1 变为形如 [a+1,a+1,a+1] 的三元组即可将 dp[a][i][j] 转移至 dp[a+1][j][k]
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int N, M;
int Cnt[maxn];
int Dp[maxn][5][5];
int main(int argc, char *argv[]) {
scanf("%d%d", &N, &M);
for (int i = 1, X; i <= N; ++i) {
scanf("%d", &X);
Cnt[X]++;
}
for (int a = 0; a <= M; ++a) {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
if (i + j + k <= Cnt[a]) {
Dp[a + 1][j][k] = max(Dp[a + 1][j][k], Dp[a][i][j] + k + (Cnt[a] - i - j - k) / 3);
}
}
}
}
}
printf("%d\n", Dp[M + 1][0][0]);
return 0;
}
E. Magic Stones
Description:
Grigory has n magic stones, conveniently numbered from 1 to n. The charge of the i-th stone is equal to ci.
Sometimes Grigory gets bored and selects some inner stone (that is, some stone with index i, where 2≤i≤n−1), and after that synchronizes it with neighboring stones. After that, the chosen stone loses its own charge, but acquires the charges from neighboring stones. In other words, its charge ci changes to ci′=ci+1+ci−1−ci.
Andrew, Grigory’s friend, also has n stones with charges ti. Grigory is curious, whether there exists a sequence of zero or more synchronization operations, which transforms charges of Grigory’s stones into charges of corresponding Andrew’s stones, that is, changes ci into ti for all i?
Input:
The first line contains one integer n ( 2≤n≤105) — the number of magic stones.
The second line contains integers c1,c2,…,cn ( 0≤ci≤2⋅109) — the charges of Grigory’s stones.
The second line contains integers t1,t2,…,tn ( 0≤ti≤2⋅109) — the charges of Andrew’s stones.
Output
If there exists a (possibly empty) sequence of synchronization operations, which changes all charges to the required ones, print “Yes”.
Otherwise, print “No”.
Sample Input:
4
7 2 4 12
7 15 10 12
Sample Output:
Yes
Sample Input:
3
4 4 4
1 2 3
Sample Output:
No
题目链接
两个数列 c 和 t ,可以操作 c 数列中任意一个数 ci 改变为 ci+1+ci−1−ci ,判断经过操作后数列 c 能否改变为数列 t
设数列 c 为 [c1,c2,c3] ,其差分数组 diff 为 [diff1,diff2](diff1=c2−c1,diff2=c3−c2)
若将数列 c 中 c2 改变为 c1+c3−c2 那么 c 现在为 [c1,c1+c3−c2,c3] ,则其差分数组为 [diff2,diff1]
因为 (c1+c3−c2)−c1=c3−c2=diff2,c3−(c1+c3−c2)=c2−c1=diff1 ,所以通过操作仅可调换操作数左右差分数组的次序,那么就可以根据差分数组是否相等即可判断数列 c 是否可以通过操作改变为数列 t
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int N;
ll C[maxn];
ll T[maxn];
ll CDiff[maxn];
ll TDiff[maxn];
int main(int argc, char *argv[]) {
scanf("%d", &N);
for (int i = 1; i <= N; ++i) scanf("%lld", &C[i]);
for (int i = 1; i <= N; ++i) scanf("%lld", &T[i]);
if (C[1] != T[1] || C[N] != T[N]) {
printf("No\n");
return 0;
}
for (int i = 2; i <= N; ++i) CDiff[i] = C[i] - C[i - 1];
for (int i = 2; i <= N; ++i) TDiff[i] = T[i] - T[i - 1];
sort(CDiff + 2, CDiff + N + 1);
sort(TDiff + 2, TDiff + N + 1);
for (int i = 2; i <= N; ++i) {
if (CDiff[i] != TDiff[i]) {
printf("No\n");
return 0;
}
}
printf("Yes\n");
return 0;
}
F. Nearest Leaf
Description:
Let’s define the Eulerian traversal of a tree (a connected undirected graph without cycles) as follows: consider a depth-first search algorithm which traverses vertices of the tree and enumerates them in the order of visiting (only the first visit of each vertex counts). This function starts from the vertex number 1 and then recursively runs from all vertices which are connected with an edge with the current vertex and are not yet visited in increasing numbers order. Formally, you can describe this function using the following pseudocode:
next_id = 1
id = array of length n filled with -1
visited = array of length n filled with false
function dfs(v):
visited[v] = true
id[v] = next_id
next_id += 1
for to in neighbors of v in increasing order:
if not visited[to]:
dfs(to)
You are given a weighted tree, the vertices of which were enumerated with integers from 1 to n using the algorithm described above.
A leaf is a vertex of the tree which is connected with only one other vertex. In the tree given to you, the vertex 1 is not a leaf. The distance between two vertices in the tree is the sum of weights of the edges on the simple path between them.
You have to answer q queries of the following type: given integers v, l and r, find the shortest distance from vertex v to one of the leaves with indices from l to r inclusive.
Input:
The first line contains two integers n and q ( 3≤n≤500000,1≤q≤500000) — the number of vertices in the tree and the number of queries, respectively.
The (i−1)-th of the following n−1 lines contains two integers pi and wi ( 1≤pi<i,1≤wi≤109), denoting an edge between vertices pi and i with the weight wi.
It’s guaranteed that the given edges form a tree and the vertices are enumerated in the Eulerian traversal order and that the vertex with index 1 is not a leaf.
The next q lines describe the queries. Each of them contains three integers vi, li, ri ( 1≤vi≤n,1≤li≤ri≤n), describing the parameters of the query. It is guaranteed that there is at least one leaf with index x such that li≤x≤ri.
Output
Output q integers — the answers for the queries in the order they are given in the input.
Sample Input:
5 3
1 10
1 1
3 2
3 3
1 1 5
5 4 5
4 1 2
Sample Output:
3
0
13
Sample Input:
5 3
1 1000000000
2 1000000000
1 1000000000
1 1000000000
3 4 5
2 1 5
2 4 5
Sample Output:
3000000000
1000000000
2000000000
Sample Input:
11 8
1 7
2 1
1 20
1 2
5 6
6 2
6 3
5 1
9 10
9 11
5 1 11
1 1 4
9 4 8
6 1 4
9 7 11
9 10 11
8 1 11
11 4 5
Sample Output:
8
8
9
16
9
10
0
34
题目链接
一棵以 1 为根的 n 个节点有根带权树,对每次询问 v l r 求以 v 为起点到编号为 [l,r] 内叶子节点的最近距离(题目保证 [l,r] 内至少有一个叶子节点)
发现题目树上节点编号正好对应dfs序编号,所以可以利用dfs序求出每个节点到根节点的距离(题目只要求叶子节点所以非叶子节点的距离直接设为 inf 即可)并用线段树维护
考虑离线处理每次询问
由根节点开始dfs整棵树,假设dfs枚举节点为 cur 对于每个 cur 为查询起点的询问其结果为 [l,r] 距离中的最小值,每次向下搜索到 son[cur] 时 son[cur] 其子树中节点两两之间距离减 2×dis(cur,son[cur]) ,这里利用dfs序加线段树区间修改即可实现
此题若用链式前向星建图则节点编号顺序不对应
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e18;
const int maxn = 5e5 + 5;
//------Graph------
struct Edge {int V, Weight;};
vector<Edge> edges[maxn];
//------Segment Tree----
ll Val[maxn];
struct SegmentTree {
ll Dis[maxn << 2];
ll Lazy[maxn << 2];
void PushUp(int Root) {
Dis[Root] = min(Dis[Root << 1], Dis[Root << 1 | 1]);
}
void PushDown(int Root) {
if (!Lazy[Root]) return;
Lazy[Root << 1] += Lazy[Root];
Lazy[Root << 1 | 1] += Lazy[Root];
Dis[Root << 1] += Lazy[Root];
Dis[Root << 1 | 1] += Lazy[Root];
Lazy[Root] = 0;
}
void Build(int Left, int Right, int Root) {
if (Left == Right) {
Dis[Root] = Val[Left];
return;
}
int Mid = (Left + Right) >> 1;
Build(Left, Mid, Root << 1);
Build(Mid + 1, Right, Root << 1 | 1);
PushUp(Root);
}
void Update(int OperateLeft, int OperateRight, int Value,
int Left, int Right, int Root) {
if (OperateLeft <= Left && OperateRight >= Right) {
Lazy[Root] += Value;
Dis[Root] += Value;
return;
}
PushDown(Root);
int Mid = (Left + Right) >> 1;
if (OperateLeft <= Mid) Update(OperateLeft, OperateRight, Value, Left, Mid, Root << 1);
if (OperateRight > Mid) Update(OperateLeft, OperateRight, Value, Mid + 1, Right, Root << 1 | 1);
PushUp(Root);
}
ll Query(int OperateLeft, int OperateRight, int Left, int Right, int Root) {
if (OperateLeft <= Left && OperateRight >= Right) return Dis[Root];
PushDown(Root);
int Mid = (Left + Right) >> 1;
ll Ans = INF;
if (OperateLeft <= Mid) Ans = min(Ans, Query(OperateLeft, OperateRight, Left, Mid, Root << 1));
if (OperateRight > Mid) Ans = min(Ans, Query(OperateLeft, OperateRight, Mid + 1, Right, Root << 1 | 1));
return Ans;
}
};
SegmentTree SGT;
//------Dfs Order------
int DfsClock;
int In[maxn];
int Out[maxn];
void DfsOrder(int Cur, ll Dis) {
In[Cur] = ++DfsClock;
for (auto it : edges[Cur]) DfsOrder(it.V, Dis + it.Weight);
if (edges[Cur].empty()) Val[Cur] = Dis;
else Val[Cur] = INF;
Out[Cur] = DfsClock;
}
//------Query------
struct Query {int Left, Right, Id;};
vector<Query> querys[maxn];
int N, Q;
ll Ans[maxn];
void Dfs(int Cur, ll Dis) {
for (auto it : querys[Cur]) Ans[it.Id] = SGT.Query(it.Left, it.Right, 1, N, 1) + Dis;
for (auto it : edges[Cur]) {
SGT.Update(In[it.V], Out[it.V], -it.Weight * 2, 1, N, 1);
Dfs(it.V, it.Weight + Dis);
SGT.Update(In[it.V], Out[it.V], it.Weight * 2, 1, N, 1);
}
}
int main(int argc, char *argv[]) {
scanf("%d%d", &N, &Q);
for (int i = 2, U, W; i <= N; ++i) {
scanf("%d%d", &U, &W);
edges[U].push_back((Edge){i, W});
}
DfsOrder(1, 0);
SGT.Build(1, N, 1);
for (int i = 1, V, L, R; i <= Q; ++i) {
scanf("%d%d%d", &V, &L, &R);
querys[V].push_back((Query){L, R, i});
}
Dfs(1, 0);
for (int i = 1; i <= Q; ++i) printf("%lld\n", Ans[i]);
return 0;
}