2022 Blue Bridge Cup Provincial Competition C/C++ Group A Questions

Foreword: NewOJ newly launched the 2022 Blue Bridge Cup provincial competition questions. The data are all constructed by the administrator and are for reference only.

Portal: http://oj.ecustacm.cn/viewnews.php?id=1021 .

topic overview

topic Tag difficulty Supplement link
paper cutter simulation http://oj.ecustacm.cn/problem.php?id=2021
Rodent Pioneer the game ☆☆☆ http://oj.ecustacm.cn/problem.php?id=2022
to sum prefix and ☆☆ http://oj.ecustacm.cn/problem.php?id=2023
XOR Segment tree, ST STST table ☆☆☆ http://oj.ecustacm.cn/problem.php?id=2024
tree climbing beetle Expect DP DPD P , inverse element ☆☆☆☆ http://oj.ecustacm.cn/problem.php?id=2025
frog crossing the river Dichotomous answer, greedy ☆☆☆☆ http://oj.ecustacm.cn/problem.php?id=2026
longest non-decreasing subsequence Dynamic programming, segment tree ☆☆☆☆☆ http://oj.ecustacm.cn/problem.php?id=2027
scan game Computational geometry, segment tree ☆☆☆☆☆ http://oj.ecustacm.cn/problem.php?id=2028
splitting of numbers Number Theory ☆☆☆☆☆ http://oj.ecustacm.cn/problem.php?id=2029
derivation part and And look up, search ☆☆☆☆ http://oj.ecustacm.cn/problem.php?id=2030

Note: this time C++A C++\AC++  The quality of the questions in Group A is very good, but it is too difficult, and the test points of the line segment tree are repeated (there may also be other methods).

Test Question A: Paper Knife

Question meaning: 20 20 is printed on a piece of paper20 lines22 2222 columns total440 440440 QR codes, at least how many times you need to cut them all can be cut out. As shown in the figure below,2 22 rows3 33 columns need to cut9 99 times.
insert image description here

Tag: simulation

Difficulty:

Idea: According to the meaning of the question, first of all, you need to cut 4 4 additionally4 times to remove borders. 1 cut per 11 knife, can increase the number of papers by1 11 . Eventually it will become440 440440 QR codes, only need to cut439 439439 times. Total439 + 4 = 443 439+4=443439+4=443 times.

Question B: Pioneer of Rodent Control

Title meaning: in 2 22 rows4 4On a 4 -column chessboard, two people take turns to operate, and each time they can choose to place 1 1on the empty space.1 pawn, or place pawns on two consecutive empty spaces in the same row. In the end, the person who makes the board full loses.

Presence 4 4The 4 initial positions are as follows,OOO means empty,XXX means placed. Everyone places chess pieces with the optimal strategy. Judging the first hand victory (outputVVV ) or second hand wins (outputLLL)。

XOOO XXOO OXOO OXXO
OOOO OOOO OOOO OOOO

Tag: game

Difficulty: ☆☆☆

Idea: The core of the game problem:

Those who can only be transferred to the must-win state are all in the must-lose state.

Those that can be transferred to the must-lose state are all in the must-win state.

  1. First determine the final defeat state: when there is only one chess piece left, it must be defeated.

    OXXX	XOXX
    XXXX	XXXX
    
  2. Using the core mentioned above, deduce whether other situations are a must-lose state or a must-win state.

  3. Note that given 4 44 situations are the four kinds of situations of the first step of the first move, and the situation is a must-win state for this moment, which means that the second mover wins.

#include<bits/stdc++.h>
using namespace std;
///判断是否仅存在一个空格
bool check(string s)
{
    
    
    int tot = 0;
    for(auto x : s)if(x == 'O')
        tot++;
    return tot == 1;
}
map<string, bool>SG;
bool dfs(string s)
{
    
    
    if(SG.count(s))
        return SG[s];
    if(check(s))
        return SG[s] = false;
    ///模拟放1个棋子
    for(int i = 0; i < s.size(); i++)if(s[i] == 'O')
    {
    
    
        string tmp = s;
        tmp[i] = 'X';
        if(dfs(tmp) == false)///可以到达必败态均为必胜态
            return SG[s] = true;
    }
    ///模拟放2个棋子
    for(int i = 0; i < s.size() - 1; i++)if(s[i] == 'O' && s[i + 1] == 'O' && i != 3)
    {
    
    
        string tmp = s;
        tmp[i] = tmp[i + 1] = 'X';
        if(dfs(tmp) == false)///可以到达必败态均为必胜态
            return SG[s] = true;
    }
    ///运行到此,说明只能转移到必胜态,此时为必败态
    return SG[s] = false;
}

int main()
{
    
    
    string s[] = {
    
    "XOOOOOOO", "XXOOOOOO", "OXOOOOOO", "OXXOOOOO"};
    for(int i = 0; i < 4; i++)
    {
    
    
        if(dfs(s[i]))cout<<"L";///此时为必胜态,说明后手面临的局面必胜,输出L
        else cout<<"V";
    }
    return 0;
}

Question C: Summing

The meaning of the title: Given an array aaa,求 ∑ i = 1 n ∑ j = i + 1 n a i a j \sum_{i=1}^n\sum_{j=i+1}^n a_ia_j i=1nj=i+1naiaj

Tag: prefix and

Difficulty: ☆☆

∑ i = 1 n ∑ j = i + 1 naiaj = ∑ i = 1 n [ ai ∑ j = i + 1 naj ] \sum_{i=1}^n\sum_{j= i
+1}^n a_ia_j =\sum_{i=1}^n\left[a_i\sum_{j=i+1}^na_j\right]i=1nj=i+1naiaj=i=1n[aij=i+1naj[
_
_ n ] − sum [ i ] ) \sum_{i=1}^n\sum_{j=i+1}^n a_ia_j =\sum_{i=1}^n\left[a_i\sum_{j=i+ 1}^na_j\right] =\sum_{i=1}^n a_i(sum[n]-sum[i])i=1nj=i+1naiaj=i=1n[aij=i+1naj]=i=1nai(sum[n]s u m [ i ])
can preprocess the prefix sum, and the time complexity isO ( n ) O(n)O ( n )

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
ll a[maxn], sum[maxn];
int main()
{
    
    
    int n;
    ll ans = 0;
    cin >> n;
    for(int i = 1; i <= n; i++) ///预处理前缀和
        cin >> a[i], sum[i] = sum[i - 1] + a[i];
    for(int i = 1; i <= n; i++) ///求和即可
        ans += a[i] * (sum[n] - sum[i]);
    cout<<ans<<endl;
    return 0;
}

Question D: XOR

The meaning of the title: Given an array aaa and integerxxx m m m times of inquiry, each inquiry interval[ l , r ] [l,r][l,r ] Whether there are two numbers such that the XOR value is equal toxxx

Tag: line segment tree, ST STST table

Difficulty: ☆☆☆

Idea: given xxx , for the interval[ l , r ] [l,r][l,r ] for each numbera[ i ] a[i]a [ i ] , only need to judge the interval[ l , r ] [l,r][l,r ] Is therea [ i ] ⊕ xa[i]\oplus xa[i]x

Violent judgment will time out, how to quickly judge the interval [ l , r ] [l,r][l,r ] instead ofa [ i ] a[i]a [ i ] to judge?

For each number a [ i ] a[i]a [ i ] , find the nearesta [ j ] a[j]a [ j ] , satisfyinga[i] ⊕ a[j] = xa[i]\oplus a[j]=xa[i]a [ j ]=x,则 < j , i > <j,i> <j,i> A two-tuple is a legal solution wherej < i j<ij<i

Why must it be the closest legal position on the left instead of the closest on the right?

The two are the same, because the nearest legal position to the left found by i is jjdddThe closest right side found by j is iii

for each iii , find the nearest legaljjj,记为 L e f t [ i ] = j Left[i]=j Left[i]=j,满足 j < i , a [ i ] ⊕ a [ j ] = x j<i,a[i]\oplus a[j]=x j<i,a[i]a [ j ]=x

Then for the query [ l , r ] [l,r][l,r ] Whether there are two digital XOR values ​​equal toxxx , which is equivalent toasking [ l , r ] [l,r][l,r ] is there aniii type:l ≤ i ≤ r , l ≤ Left [ i ] l\le i \le r,l\le Left[i]lir,lLeft[i]

there is an iii can satisfy the condition, which is equivalent to the largestLeft [ i ] Left[i]L e f t [ i ] greater thanlll input, ifl ≤ Max { Left [ i ] ∣ l ≤ i ≤ r } l \le Max\{Left[i]|l\le i \le r\}lMax{ Left[i]lir}

The problem is converted into: the problem of finding the maximum value of the interval, using the line segment tree or ST STST table is enough.

How to quickly get Left LeftLeft array ? _ _ When traversing from left to right, usepos [ x ] pos[x]p os [ x ] record numberxxThe position where x appeared last time, thenLeft [ i ] = pos [ a [ i ] ⊕ x ] Left[i]=pos[a[i]\oplus x]Left[i]=pos[a[i]x]

Note: This question can also use the Mo team algorithm to maintain the interval XOR equal to xxx times to solve.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int tree[maxn << 2];
int Left[maxn], pos[(1 << 20) + 10];
int a[maxn], n, m, x;

//线段树模板
void build(int o, int l, int r)
{
    
    
    if(l == r)
    {
    
    
        tree[o] = Left[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    tree[o] = max(tree[o << 1], tree[o << 1 | 1]);
}
int query(int o, int l, int r, int L, int R)
{
    
    
    if(L <= l && r <= R)return tree[o];
    int mid = (l + r) >> 1;
    int ans = 0;
    if(L <= mid)ans = max(ans, query(o << 1, l, mid, L, R));
    if(R > mid)ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R));
    return ans;
}

int main()
{
    
    
    scanf("%d%d%d", &n, &m, &x);
    for(int i = 1; i <= n; i++) //预处理Left数组
    {
    
    
        scanf("%d", &a[i]);
        Left[i] = pos[a[i] ^ x];
        pos[a[i]] = i;
    }
    build(1, 1, n);//线段树建树
    while(m--)
    {
    
    
        int l, r;
        scanf("%d%d", &l, &r);
        if(query(1, 1, n, l, r) >= l)//查询区间最值
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}

Test Question E: A Beetle Climbing a Tree

Meaning of the title: The Beetle wants to climb to a height of nnA tree of n , starting at the root with height 0, when it tries to go from heighti − 1 i-1i1 climbed to heightiiWhen the position of i hasP i P_iPiThe probability will fall back to the root of the tree, and what is the expected value of the elapsed time when it climbs from the root to the top of the tree.

Tag: expect DP DPD P , inverse element

Difficulty: ☆☆☆☆

Idea: dp [ i − 1 ] dp[i-1]dp[i1 ] means from heighti − 1 i-1i1 The expected time it takes to get to the top. According to the title, the following state transition equation can be obtained:
dp [ i − 1 ] = P i ∗ dp [ 0 ] + ( 1 − P i ) dp [ i ] + 1 dp [ n ] = 0 \begin{aligned} dp [i-1]&=P_i*dp[0]+(1-P_i)dp[i] + 1 \\ dp[n]&=0 \end{aligned}dp[i1]dp[n]=Pidp[0]+(1Pi)dp[i]+1=0
利用递推式展开:
d p [ n ] = 0 ∗ d p [ 0 ] + 0 = a ∗ d p [ 0 ] + b d p [ n − 1 ] = P n ∗ d p [ 0 ] + ( 1 − P n ) d p [ n ] + 1 d p [ n − 2 ] = P n − 1 ∗ d p [ 0 ] + ( 1 − P n − 1 ) d p [ n − 1 ] + 1 . . . d p [ 0 ] = P 1 d p [ 0 ] + ( 1 − P 1 ) d p [ 1 ] + 1 \begin{aligned} dp[n]&=0*dp[0]+0=a*dp[0]+b \\ dp[n-1]&=P_n * dp[0] + (1-P_n)dp[n] + 1 \\ dp[n-2]&=P_{n-1} * dp[0] + (1-P_{n-1})dp[n-1] + 1 \\ ... \\ dp[0]&=P_1dp[0]+(1-P_1)dp[1]+1 \end{aligned} dp[n]dp[n1]dp[n2]...dp[0]=0dp[0]+0=adp[0]+b=Pndp[0]+(1Pn)dp[n]+1=Pn1dp[0]+(1Pn1)dp[n1]+1=P1dp[0]+(1P1)dp[1]+1
Maintain two variables a , ba, ba,b , respectively representdp [ 0 ] dp[0]Coefficients and constants of d p [ 0 ] , initially both are 0.

dp [n] dp[n]d p ​​[ n ] substitutedp [ n − 1 ] dp[n-1]dp[n1 ] , get newa, ba, ba,b
a = P n + ( 1 − P n ) ∗ a b = 1 + ( 1 − P n ) ∗ b \begin{aligned} a&=P_n+(1-P_n)*a \\ b&=1+(1-P_n)*b \end{aligned} ab=Pn+(1Pn)a=1+(1Pn)b
Finally, we can get:
dp [ 0 ] = a ∗ dp [ 0 ] + b dp[0]=a*dp[0]+bdp[0]=adp[0]+In b
traversal, all numbers in the modulo sense are used to solvedp [ 0 ] dp[0]When d p [ 0 ]
is equivalent to solving: ( a − 1 ) dp [ 0 ] + b ≡ 0 % MOD (a-1)dp[0]+b\equiv0\% MOD(a1)dp[0]+b0% MO D
use extended Euclidean to solvedp [ 0 ] dp[0]d p ​​[ 0 ] is enough.

Note: There is a better way, the recursion process is more complicated, but the final extended Euclidean is not required.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const int MOD = 998244353;
ll x[maxn], y[maxn];
ll ksm(ll a, ll b, ll m)
{
    
    
    ll ans = 1;
    while(b)
    {
    
    
        if(b & 1)ans = ans * a % m;
        b >>= 1;
        a = a * a % m;
    }
    return ans;
}
ll inv(ll x)
{
    
    
    return ksm(x, MOD - 2, MOD);
}
ll extgcd(ll a, ll b, ll&x, ll&y)//ax+by = gcd(a, b)的解。返回值为gcd
{
    
    
    ll d = a;
    if(b)
    {
    
    
       d = extgcd(b, a % b, y, x);
       y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return d;
}

int main()
{
    
    
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
    
    
        cin >> x[i] >> y[i];
        ll g = __gcd(x[i], y[i]);
        x[i] = x[i] / g;
        y[i] = y[i] / g;
    }
    ll a = 0, b = 0;
    for(int i = n; i >= 1; i--)
    {
    
    
        ll p = x[i] * inv(y[i]) % MOD, p_1 = (y[i] - x[i]) * inv(y[i]) % MOD;
        a = (p + p_1 * a) % MOD;
        b = (1 + p_1 * b) % MOD;
    }
    ///cout<<x[1]<<" "<<y[1]<<" "<<inv(y[1])<<endl;
    ///dp[0] = a * dp[0] + b
    ///(a-1)dp[0]+k * MOD = MOD - b
    ///(a - 1)x + MOD * y = MOD - b
    ///cout<<a<<" "<<b<<endl;
    ll c = a - 1, d = MOD, x, y;
    ll g = extgcd(c, d, x, y);
    ///cout<<x<<" "<<y<<endl;
    ll x1 = x * (MOD - b) / g;
    ll y1 = y * (MOD - b) / g;
    cout<<(x1 % MOD + MOD ) % MOD<<endl;
    return 0;
}

Question F: Frogger across the river

Title meaning: The little frog lives by a river, and it wants to study at the school on the other side of the river. The little frog was going to jump across the stones in the river to the other bank. The stones in the river are lined up in a straight line, and every time the little frog jumps, it must land on a stone or on the bank. However, each stone has a height. Every time the little frog jumps from a stone, the height of the stone will drop by 1. When the height of the stone drops to 0, the little frog can no longer jump on the stone (a certain jump It is allowed to drop the stone height to 0 afterwards).

The little frog needs to go to school in total xxx zakat so it takes2 x 2x2 x times. When the little frog has a jumping abilityyyy , it can jump no more thanyyy -distance. May I ask what is the minimum jumping ability of the little frog to use these stones to finishxxx lessons.

Tag: two-point answer, greedy

Difficulty: ☆☆☆☆

Idea: Round trip cumulative 2 x 2x2 x times is equivalent to walking2 x 2x2 x times. The bigger the jump ability, the more guaranteed you can pass2 x 2x2 x times. Therefore, the binary answer can be used to find a minimum jumping ability that satisfies the condition.

Assuming the jump ability is mid midmid , one idea is to jump as far as you can jump each time, and then simulate and judge mid midWhether mid is legal or not, the practice is more complicated and will not be expanded for now.

Another idea is to judge each length as mid midWhether the sum of the intervals of mid is greater than or equal to2 x 2x2 x , if each interval sums greater than2 x 2x2 x , it is guaranteed to construct a set of solutions through2 x 2x2 x times. Conversely, you can think about whether it is true.

Reference: https://www.zhihu.com/question/525176453/answer/2433729894 .

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
template <typename T>
inline T read(T& x) {
    
    
  x = 0;
  T w = 1;
  char ch = 0;
  while (ch < '0' || ch > '9') {
    
    
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    
    
    x = x * 10 + (ch - '0');
    ch = getchar();
  }
  return x * w;
}
int h[maxn], sum[maxn];
int n, x;
//判断所有长度为mid的区间之和是否大于等于2x
bool check(int mid)
{
    
    
    for(int i = 1; i + mid - 1 <= n; i++)
        if(sum[i + mid - 1] - sum[i - 1] < 2 * x)return false;
    return true;
}
int main()
{
    
    
    read(n); read(x);
    for(int i = 1; i <= n - 1; i++)//预处理前缀和
        read(h[i]), sum[i] = sum[i - 1] + h[i];
    sum[n] = 1e9 + 7;
    int left = 1, right = n, ans = n;
    while(left <= right)//二分答案
    {
    
    
        int mid = (left + right) >> 1;
        if(check(mid))
            ans = mid, right = mid - 1;//求最小合法解
        else
            left = mid + 1;
    }
    cout<<ans<<endl;
    return 0;
}

Question G: The longest non-decreasing subsequence

The meaning of the title: Given an array aaa , can modify consecutiveKKK numbers become one same value. Please calculate the modified longest non-decreasing subsequence length.

Tag: dynamic programming, line segment tree

Difficulty: ☆☆☆☆☆

Idea: The longest non-decreasing subsequence is a classic dynamic programming problem. This question is only related to the size of the number and has nothing to do with the value. Therefore, first discretize the array.

d p [ i ] dp[i] d p ​​[ i ] meansa [ i ] a[i]The length of the longest non-decreasing subsequence at the end of a [ i ] , for modified continuousKKK numbers become the same value, it is best to modify it to the same number as before, namely:

Modification a [ i − k + 1 ] , . . . , a [ i ] a[i-k+1],...,a[i]a[ik+1],...,a [ i ] uniform modificationa [ i − k ] a[ik]a[ik ] , the longest ascending subsequence at this time can be regarded as 3 segments:

  1. [ 1 , i − k ] [1,i-k] [1,ik ] : lengthdp [ i − k ] dp[ik]dp[ik]
  2. [ i − k + 1 , . . . , i − 1 ] [i-k+1,...,i-1] [ik+1,...,i1 ] : lengthk − 1 k-1k1
  3. [ i , i + 1... n ] [i,i+1...n] [i,i+1...n] a [ i ] , a [ i + 1 ] , . . . , a [ n ] a[i],a[i+1],...,a[n] a[i],a[i+1],...,in a [ n ] , a[i]a[i]The longest ascending subsequence starting with a [ i ] , pay attention to a [ i ] a[i]a [ i ]的值应用等于a [ i − k ] a[ik]a[ik]

In order to find dp [ i ] dp[i]d p ​​[ i ] , use the weight line segment tree to finddp [ 1 ] , . . . , dp [ i − 1 ] dp[1],...,dp[i-1]dp[1],...,dp[i1 ] largest numberdp[j] dp[j]d p ​​[ j ] , simultaneous guaranteea [ j ] ≤ a [ i ] a[j]\le a[i]a [ j ]a[i]

The specific method is: for aaAfter the a array is discretized, traverseaaa several pairs, generala [ i ] a[i]a [ i ] is regarded as the first a [ i ] a[i]of the line segment treea[i]位, d p [ i ] dp[i] d p ​​[ i ] is the value maintained by the line segment tree (the maximum value maintained by the line segment tree), query the line segment tree interval[ 1 , a [ i ] ] [1,a[i]][1,a [ i ]] is the maximum value.

Similarly, reverse traversal, each query [ a [ i ] , n ] [a[i],n][a[i],The maximum value of n ] can be maintained withxxThe longest ascending subsequence at the beginning of x , so that each section of KKJust K.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
template <typename T>
inline T read(T& x) {
    
    
  x = 0;
  T w = 1;
  char ch = 0;
  while (ch < '0' || ch > '9') {
    
    
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    
    
    x = x * 10 + (ch - '0');
    ch = getchar();
  }
  return x * w;
}
int a[maxn], b[maxn];
int dp[maxn];
///dp[i]表示以i结尾的最长上升子序列

///权值线段树,维护dp数组
int tree[maxn << 2];
void build(int o, int l, int r)
{
    
    
    tree[o] = 0;
    if(l == r)return;
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
}
void update(int o, int l, int r, int x, int val)
{
    
    
    if(l == r)
    {
    
    
        tree[o] = max(tree[o], val);
        return;
    }
    int mid = (l + r) >> 1;
    if(x <= mid)update(o << 1, l, mid, x, val);
    else update(o << 1 | 1, mid + 1, r, x, val);
    tree[o] = max(tree[o << 1], tree[o << 1 | 1]);
}
int query(int o, int l, int r, int L, int R)
{
    
    
    if(L <= l && r <= R)
        return tree[o];
    int mid = (l + r) >> 1;
    int ans = 0;
    if(L <= mid)ans = max(ans, query(o << 1, l, mid, L, R));
    if(R > mid)ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R));
    return ans;
}

int main()
{
    
    
    int n, k, tot = 0;
    read(n); read(k);
    for(int i = 1; i <= n; i++)read(a[i]), b[++tot] = a[i];
    if(n == k)
    {
    
    
        cout<<n<<endl;
        return 0;
    }
    ///离散化
    sort(b + 1, b + 1 + tot);
    tot = unique(b + 1, b + 1 + tot) - (b + 1);
    for(int i = 1; i <= n; i++)
        a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
    
    build(1, 1, tot);
    int ans = 0;
    for(int i = 1; i <= n; i++)///从前往后遍历a,放入权值线段树中
    {
    
    
        ///dp[i] = max(dp[j]) 满足j=1...i-1 && a[j] <= a[i]
        dp[i] = query(1, 1, tot, 1, a[i]) + 1;
        update(1, 1, tot, a[i], dp[i]);
    }
    ///重新清空
    build(1, 1, tot);
    for(int i = n; i > k; i--)///从后往前遍历a,放入权值线段树中
    {
    
    
        ///a[i-k+1] ... a[i]相等 均等于a[i-k]
        ///最后一段要注意:查询的是[a[i-k],tot]中的最大值
        ans = max(ans, dp[i - k] + k - 1 + query(1, 1, tot, a[i - k], tot) + 1);
        int tmp = query(1, 1, tot, a[i], tot) + 1; ///以a[i]开始的最长上升子序列长度
        ans = max(ans, tmp + k);
        ///插入的是a[i]
        update(1, 1, tot, a[i], tmp);
    }
    cout<<ans<<endl;
    return 0;
}

Question H: Scanning Game

The meaning of the title: There is a root around the origin OOO clockwise rotating stickOA OAO A , initially pointing directly up (YYpositive Y axis). There are several objects in the plane,iiThe coordinates of the i object are( xi , yi ) (xi, yi)(xi,y i ) , to bezi ziz i . When the stick sweeps to an object, the length of the stick will increasezi ziz i , and the object disappears instantly (the top of the stick just touches the object and it is considered as being swept), if the grown stick touches other objects at this time, it will also be eliminated in the above way (it is regarded as the same time as the above point) disappear).

If the objects are sorted according to the disappearance time, each object has a rank, and the ranks of the disappearing objects are the same, please output the rank of each object, if the object will never disappear, output − 1 -11

Tag: computational geometry, line segment tree

Difficulty: ☆☆☆☆☆

Idea: first sort the polar angles and sort them clockwise. Specifically, quadrant + cross product can be used to sort.

The initial rod length is LLL , every time you need to find the first clockwise less than or equal toLLThe point of L is enough.

The line segment tree can be used to maintain the distance from each point to the origin xi 2 + yi 2 x_i^2+y_i^2xi2+yi2, to find the next less than or equal to L 2 L^2L2 , thus maintaining a minimum value.

Assuming the previous position was last lastl a s t (initially 0), each time using the line segment tree to find the interval[ last + 1 , n ] [last+1,n][last+1,n ] , the first one from left to right is less than or equal toL 2 L^2LThe number of 2 , if not found, look for the interval[ 1 , last − 1 ] [1,last-1][1,last1 ] The first one from left to right is less than or equal toL 2 L^2L2 digits (one circle clockwise).

Terminate if not found.

If found, mark it as idx idxi d x . Rod lengthLLLincrease zidx z_{idx}zidx, record the current idx idxThe answer of i d x points. Note that if the angle between the current point and the previous point is 0, the ranking is the same.

code due to LLL keeps increasing,L 2 L^2L2 will exceedlong long long\ longl o n g l o n g  , you can maintain the distance in the code instead of the square of the distance, or you can use_ _ int 128 \_\_int128__ in t 128 to maintain variableL 2 L^2L2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 7;
const int maxn = 2e5 + 10;
template <typename T>
inline T read(T& x) {
    
    
  x = 0;
  T w = 1;
  char ch = 0;
  while (ch < '0' || ch > '9') {
    
    
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    
    
    x = x * 10 + (ch - '0');
    ch = getchar();
  }
  return x = x * w;
}
struct point
{
    
    
    ll x, y, z;
    int id;
}a[maxn];
ll n;
__int128 L;

int Quadrant(point a)
{
    
    
    if(a.x >= 0 && a.y > 0)return 1;///y的正半轴放到第一象限
    if(a.x > 0 && a.y <= 0)return 2;///x的正半轴放到第二象限
    if(a.x <= 0 && a.y < 0)return 3;
    return 4;
}
ll cross(point a, point b)
{
    
    
    return a.x * b.y - a.y * b.x;
}
bool cmp(point a, point b)
{
    
    
    if(Quadrant(a) == Quadrant(b))
    {
    
    
        if(cross(a, b) == 0)
            return a.x * a.x + a.y * a.y < b.x * b.x + b.y * b.y;
        else
           return cross(a, b) < 0;
    }
    else
        return Quadrant(a) < Quadrant(b);
}

__int128 mi[maxn << 2];
void push_up(int o)
{
    
    
    mi[o] = min(mi[o << 1], mi[o << 1 | 1]);
}
void build(int o, int l, int r)
{
    
    
    if(l == r)
    {
    
    
        mi[o] = a[l].x * a[l].x + a[l].y * a[l].y;
        return ;
    }
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    push_up(o);
}

void update(int o, int l, int r, int x, __int128 val)
{
    
    
    if(l == r)
    {
    
    
        mi[o] = val;
        return;
    }
    int mid = (l + r) >> 1;
    if(x <= mid)update(o << 1, l, mid, x, val);
    else update(o << 1 | 1, mid + 1, r, x, val);
    push_up(o);
}

///找右边第一个小于等于z^2的数字
ll idx;
bool query(int o, int l, int r, int L, int R, __int128 z)
{
    
    
    if(L > R)return false;
    if(l == r)
    {
    
    
        idx = l;
        return mi[o] <= z;
    }
    int mid = (l + r) >> 1;
    if(L <= mid)
    {
    
    
        if((mi[o << 1] <= z) && query(o << 1, l, mid, L, R, z))
            return true;
    }
    if(R > mid)
    {
    
    
        if((mi[o << 1 | 1] <= z) && query(o << 1 | 1, mid + 1, r, L, R, z))
            return true;
    }
    return false;
}
int ans[maxn];

int main()
{
    
    
    read(n);read(L);
    for(int i = 1; i <= n; i++)
    {
    
    
        read(a[i].x);read(a[i].y);read(a[i].z);
        a[i].id = i;
        ans[i] = -1;
    }
    sort(a + 1, a + 1 + n, cmp);
    build(1, 1, n);
    int cnt = 0;
    int lastcnt = 0;
    int last = 0;  ///上一个位置
    while(true)
    {
    
    
        bool ok = query(1, 1, n, last + 1, n, L * L);
        if(ok)L = L + a[idx].z;
        else
        {
    
    
            ok = query(1, 1, n, 1, last - 1, L * L);
            if(ok)L = L + a[idx].z;
            else break;
        }
        update(1, 1, n, idx, 1e32);
        if(last)
        {
    
    
            if(Quadrant(a[last]) == Quadrant(a[idx]) && cross(a[last], a[idx]) == 0)
                ans[a[idx].id] = lastcnt, ++cnt;
            else
                ans[a[idx].id] = ++cnt, lastcnt = cnt;
        }
        else
            ans[a[idx].id] = ++cnt, lastcnt = cnt;
        last = idx;
    }
    for(int i = 1; i <= n; i++)
    {
    
    
        cout<<ans[i];
        if(i != n)cout<<" ";
    }
    return 0;
}

Question I: Splitting Numbers

Meaning of the question: Judgment number a ≤ 1 0 18 a \le 10^{18}a10Can 18 be expressed asx 1 y 1 x 2 y 2 x_1^{y_1}x_2^{y_2}x1y1x2y2of the form, where x 1 , x 2 x_1,x_2x1,x2is a positive integer, y 1 , y 2 y_1,y_2y1,y2is greater than or equal to 2 2A positive integer of 2 . T ≤ 100000 T \le 100000T100,000 inquiries.

Tag: number theory

Difficulty: ☆☆☆☆☆

Idea: first consider the aaa for prime factorizationp 1 q 1 p 2 q 2 ⋅ . . . ⋅ pkqk p_1^{q_1}p_2^{q_2}\cdot ...\cdot p_k^{q_k}p1q1p2q2...pkqk, firstly to satisfy qi ≥ 2 q_i\ge 2qi2

∀ q i ≥ 2 \forall q_i \ge 2 qi2 , to be split intok 1 ∗ y 1 + k 2 ∗ y 2 = qi k_1*y_1+k_2*y_2=q_ik1y1+k2y2=qi k 1 , k 2 ≥ 0 , y 1 , y 2 ≥ 2 k_1,k_2 \ge 0,y_1,y_2\ge 2 k1,k20,y1,y22

y1 = 2 , y2 = 3 y_1=2,y_2=3y1=2,y2=3 can guarantee that allqi ≥ 2 q_i \ge 2qi2 have non-negative integer solutions.

2 k 1 + 3 k 2 = k 2k_1+3k_2=k 2 k1+3 k2=k for∀ k > 1 \forall k > 1k>1 has nonnegative integer solutions:

1、 k % 3 = = 0 k\%3==0 k%3==0 :k 1 = 0 , k 2 = k 3 k_1=0,k_2=\frac{k}{3}k1=0,k2=3k

2、 k % 3 = = 1 k\%3==1 k%3==1 :k 1 = 2 , k 2 = k − 4 3 k_1=2,k_2=\frac{k-4}{3}k1=2,k2=3k4

3、 k % 3 = = 2 k\%3==2 k%3==2 :k 1 = 1 , k 2 = k − 2 3 k_1=1,k_2=\frac{k-2}{3}k1=1,k2=3k2

So the problem becomes the number aaCan a becomex 1 2 x 2 3 x_1^2x_2^3x12x23

If = p 1 q 1 p 2 q 2 ⋅ . . . . . . . . ⋅ pkqka=p_1^{q_1}p_2^{q_2}\cdot ...\cdot p_k^{q_k}a=p1q1p2q2...pkqk, only need to detect each qi q_iqiIs it greater than or equal to 2 22 is fine, as long as it is greater than or equal to2 22 , you can follow the correspondingk 1 , k 2 k_1,k_2k1,k2assigned to x 1 , x 2 x_1,x_2x1,x2in.

Because a ≤ 1 0 18 a\le 10^{18}a1018 , sox 1 2 x 2 3 ≤ 1 0 18 x_1^2x_2^3\le 10^{18}x12x231018 . If prime factorp > 4000 p>4000p>4000 ,p 5 ≥ 1 0 18 p^5\ge 10^{18}p51018 . So only violent judgment is needed4000 4000Prime factor within 4000 , for more than 4000 40004000pp __p , the index can only be2 , 3 , 4 2,3,42,3,4 , just judge whether it is a square number or a cubic number.

Time complexity O ( T ∗ 550 ) O(T*550)O(T550) 550 550 550 is4000 4000The number of prime numbers within 4000 .

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
template <typename T>
inline T read(T& x) {
    
    
  x = 0;
  T w = 1;
  char ch = 0;
  while (ch < '0' || ch > '9') {
    
    
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    
    
    x = x * 10 + (ch - '0');
    ch = getchar();
  }
  return x * w;
}

bool not_prime[4010];
int prime[4010], tot;
void init(int n)
{
    
    
    for(int i = 2; i <= n; i++)if(!not_prime[i])
    {
    
    
        prime[++tot] = i;
        for(int j = i + i; j <= n; j += i)
            not_prime[j] = 1;
    }
}
inline bool check(ll x)
{
    
    
    ///检查平方数
    ll y = pow(x, 0.5);
    if(y * y == x || (y + 1) * (y + 1) == x)
        return true;
    ///检查立方数
    y = pow(x, 1.0 / 3);
    if(y * y * y == x || (y + 1) * (y + 1) * (y + 1) == x || (y + 2) * (y + 2) * (y + 2) == x)
        return true;
    return false;
}
int main()
{
    
    
    init(4000);
    int T;
    read(T);
    while(T--)
    {
    
    
        ll x;
        read(x);
        if(check(x))
        {
    
    
            puts("yes");
            continue;
        }
        bool flag = true;
        for(int i = 1; i <= tot; i++)if(x % prime[i] == 0){
    
    
            int now = 0;
            while(x % prime[i] == 0)
            {
    
    
                now++;
                x /= prime[i] ;
            }
            ///cout<<prime[i]<<" "<<now<<endl;
            if(now == 1)
            {
    
    
                flag = false;
                break;
            }
        }
        if(flag & check(x))
        {
    
    
            puts("yes");
            continue;
        }
        else
        {
    
    
            puts("no");
        }
    }
    return 0;
}

Question J: Derivation Part and

The meaning of the title: For the sequence aaa , given some interval sums, ask for several interval sums.

Tag: union search, search

Difficulty: ☆☆☆☆

Idea: For a known interval [ l , r ] [l,r][l,The sum of r ] issss with prefixsum [ r ] − sum [ l − 1 ] = s sum[r]-sum[l-1]=ssum[r]s u m [ l1]=s means that according to the differential constraint mapping criterion, it is equivalent to the pointl − 1 l-1l1 to pointrrr length issss r r r tol − 1 l-1l1 length is− s -ss

After the graph is built, ask for an interval [ ql , qr ] [ql,qr] each time[ql,q r ] , which is equivalent to askingsum [ qr ] − sum [ ql − 1 ] sum[qr]-sum[ql-1]sum[qr]sum[ql1 ] value.

First of all, we must ensure that ql − 1 ql-1ql1 andqr qrq r is in the same connected block, and each connected block only needs to be initialized to0 00 , and then expand according to the side length. This is due to the equal sign, no matter how you go, the relative difference remains unchanged.

dfs dfs in codedf s andbfs bfsBoth b f s are fine.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template <typename T>
inline T read(T& x) {
    
    
  x = 0;
  T w = 1;
  char ch = 0;
  while (ch < '0' || ch > '9') {
    
    
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    
    
    x = x * 10 + (ch - '0');
    ch = getchar();
  }
  return x = x * w;
}
const int maxn = 1e5 + 10;
const ll INF = -1e13;
int n, m, q;
struct edge
{
    
    
    int v; ll w;
    edge(){
    
    }
    edge(int v, ll w):v(v), w(w){
    
    }
};
vector<edge>Map[maxn];
ll sum[maxn];
bool vis[maxn];
void dfs(int u, ll d)
{
    
    
    vis[u] = 1;
    sum[u] = d;
    ///cout<<u<<" "<<d<<endl;
    for(auto x : Map[u])
    {
    
    
        int v = x.v; ll w = x.w;
        if(vis[v])continue;
        dfs(v, d + w);
    }
}
queue<pair<int,ll> >Q;
void bfs(int u, ll d)
{
    
    
    vis[u] = 1;
    sum[u] = d;
    Q.push(make_pair(u, d));
    while(!Q.empty())
    {
    
    
        auto now = Q.front();
        Q.pop();
        int u = now.first; ll d = now.second;
        for(auto x : Map[u])
        {
    
    
            int v = x.v; ll w = x.w;
            if(vis[v])continue;
            vis[v] = 1;
            sum[v] = d + w;
            Q.push(make_pair(v, d + w));
        }
    }
}
int f[maxn];
int Find(int x)
{
    
    
    return x == f[x] ? x : f[x] = Find(f[x]);
}
int main()
{
    
    
    read(n);read(m);read(q);
    for(int i = 0; i <= n; i++)f[i] = i;
    for(int i = 1; i <= m; i++)
    {
    
    
        int l, r; ll s;
        read(l);read(r);read(s);
        ///cout<<l<<" "<<r<<" "<<s<<endl;
        ///sum[r] - sum[l - 1] = s
        Map[l - 1].push_back(edge(r, s));
        Map[r].push_back(edge(l - 1, -s));
        f[Find(l - 1)] = Find(r);
    }
    for(int i = 0; i <= n; i++)if(!vis[i])
        bfs(i, 0);
    while(q--)
    {
    
    
        int l, r;
        read(l), read(r);
        --l;
        if(Find(l) != Find(r))puts("UNKNOWN");
        else printf("%lld\n", sum[r] - sum[l]);
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/fzl194/article/details/124347039