1. 程式人生 > 其它 >LYOI2021 歡樂模擬賽 解題報告

LYOI2021 歡樂模擬賽 解題報告

LYOI2021 歡樂模擬賽 解題報告。

A(Alive)

得分情況

全場共 \(21\)\(AC\),得分率最高。

題解

讀入 \(8\) 門科目的分數並累加,與 \(m\) 作比較即可。

#include <bits/stdc++.h>
using namespace std;
int m, x, ans;
int main() {
    cin >> m;
    for (int i = 1; i <= 8; i++) {
        cin >> x;
        ans += x;
    }
    if (ans < m)
        cout << "Die";
    else
        cout << "Live";
    return 0;
}

注意:

  1. \(ans\) 一定要設定初值或者放到全域性變數。
  2. 不要少讀入數啊,考場上有好幾位老哥讀入都沒全。
  3. 開陣列儘量開大,有一位老哥開 \(8\) 位陣列越界了,全 \(TLE\) 了。

B(Base)

得分情況

應該是全場第二簡單的題了啊,怎麼 \(AC\) 的人這麼少啊。

題解

考慮開一個 bool 陣列存出現的題目,每讀入一個數都把對應的元素設為 true,最後掃一遍陣列,統計 true 的個數。

#include <bits/stdc++.h>
using namespace std;
int q, n, m, ans, x;
bool b[10000005];
int main() {
    cin >> q >> n >> m;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &x);
        b[x] = true;
    }
    for (int i = 1; i <= m; i++) {
        scanf("%d", &x);
        b[x] = true;
    }
    for (int i = 1; i <= q; i++) {
        if (b[i] == true)
            ans++;
    }
    cout << ans;
    return 0;
}

C(Calculation)

得分情況

慘不忍睹。

題解

高精度板子。學過沒寫出來的自己反思一下。。

class High_Accuracy_Algorithm {
private:
    bool cmp(string a, string b) {
        if (a.size() < b.size())
            return true;
        if (a.size() > b.size())
            return false;
        return a < b;
    }

public:
    void Carry(string &c, int t) {
        for (; t < c.size(); t++) {
            if (c[t] - '0' >= 10) {
                int size_s = 0;
                int sum_s = c[t + size_s] - '0';
                while (sum_s) {
                    if (size_s == 0)
                        c[t] = sum_s % 10 + '0';
                    else
                        c[t + size_s] += sum_s % 10;
                    sum_s /= 10;
                    size_s++;
                }
            } else
                break;
        }
    }

    string Add(string a, string b) {
        string c(max(a.size(), b.size()) + 1, '0');
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        if (a.size() < b.size())
            a.insert(a.end(), b.size() - a.size(), '0');
        else if (b.size() < a.size())
            b.insert(b.end(), a.size() - b.size(), '0');
        for (int i = 0; i < a.size(); i++) {
            int size = 0;
            int sum = a[i] - '0' + b[i] - '0';
            while (sum) {
                c[i + size] += sum % 10;
                if (c[i + size] - '0' >= 10)
                    Carry(c, i + size);
                size++;
                sum /= 10;
            }
        }
        reverse(c.begin(), c.end());
        c = c.substr(c.find_first_not_of('0'));
        return c;
    }

    string Less(string a, string b) {
        if (a == b)
            return "0";
        bool flag = false;
        string c(max(a.size(), b.size()) + 1, '0');
        if (cmp(a, b)) {
            swap(a, b);
            flag = true;
        }
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        b.insert(b.end(), a.size() - b.size(), '0');
        for (int i = 0; i < a.size(); i++) {
            if (a[i] < b[i]) {
                for (int j = i + 1; j < a.size(); j++) {
                    if (a[j] >= '1') {
                        a[j] -= 1;
                        for (int t = j - 1; t > i; t--) a[t] = '9';
                        a[i] += 10;
                        break;
                    }
                }
            }
            c[i] += a[i] - b[i];
        }
        reverse(c.begin(), c.end());
        c = c.substr(c.find_first_not_of('0'));
        if (flag)
            c.insert(c.begin(), '-');
        return c;
    }

    string Multiply(string a, string b) {
        if (cmp(a, b))
            swap(a, b);
        string c(a.size() + b.size() + 1, '0');
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        for (int i = 0; i < b.size(); i++) {
            for (int j = 0; j < a.size(); j++) {
                int size = 0;
                int sum = (b[i] - '0') * (a[j] - '0');
                while (sum) {
                    c[i + j + size] += sum % 10;
                    if (c[i + j + size] - '0' >= 10)
                        Carry(c, i + j + size);
                    size++;
                    sum /= 10;
                }
            }
        }
        reverse(c.begin(), c.end());
        c = c.substr(c.find_first_not_of('0'));
        return c;
    }
};

string str1, str2;
High_Accuracy_Algorithm demo;

int main() {
    cin >> str1 >> str2;
    cout << demo.Add(str1, str2) << endl;
    cout << demo.Less(str1, str2) << endl;
    cout << demo.Multiply(str1, str2) << endl;
    return 0;
}

D(Difficulty)

\(70pts\)

對於每一次詢問暴力跳父親節點看結果即可,期望得分\(70\)

\(100pts\)

考慮預處理,定義一個標記陣列,初始全部為 \(1\)

先對樹做一次先序遍歷,如果遇到一個點是特殊節點,那麼他子樹內所有節點一定要經過特殊節點才能到達根節點,故將其本身與其子樹內所有節點標記為 \(0\)

最後對每次詢問輸出其標記

\(P.S.\)

\(T\)是有根樹,\(a\)\(T\)中的一個頂點,由\(a\)以及\(a\)的所有後裔(後代)匯出的子圖稱為有向樹T的子樹。

例如下圖

我們稱三角形區域為二號節點的子樹

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 7;
int fa[MAXN], ls[MAXN], rs[MAXN];
bool spe[MAXN];
bool could[MAXN];
int n, m, q;
bool flag;
void dfs(int u) {
    // cout<<u<<endl;
    if (!u)
        return;
    bool k = flag;
    if (spe[u] == 1)
        flag = 0;
    could[u] = flag;
    if (ls[u])
        dfs(ls[u]);
    if (rs[u])
        dfs(rs[u]);
    flag = k;
}
int main() {
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        fa[v] = u;
        if (!ls[u]) {
            ls[u] = v;
        } else {
            rs[u] = v;
        }
    }
    for (int i = 1; i <= m; i++) {
        int y;
        scanf("%d", &y);
        spe[y] = 1;
    }

    if (spe[1] == 0)
        flag = 1;
    else
        flag = 0;
    dfs(1);

    while (q--) {
        int x = 0;
        scanf("%d", &x);
        printf("%d\n", could[x]);
    }
    return 0;
}

E(Explore)

題解

此題為 \(BFS(廣度優先搜尋)\) 模板題。

核心程式碼:

void bfs() {
    q[tail][1] = sx;
    q[tail][2] = sy;
    q[tail][3] = 0;
    while (head <= tail) {
        int x = q[head][1], y = q[head][2], cnt = q[head][3];
        if (x == tx && y == ty) {
            printf("%d", cnt);
            exit(0);
        }
        head++;
        for (int i = 0; i < 4; i++) {
            if (a[x + dx[i]][y + dy[i]] == true) {
                tail++;
                q[tail][1] = x + dx[i];
                q[tail][2] = y + dy[i];
                q[tail][3] = cnt + 1;
                a[x + dx[i]][y + dy[i]] = false;
            }
        }
    }
}

F(Formula)

題解

本題考查對資料結構·棧的認識。利用棧儲存數字,在遇到運算子時取棧頂的兩個元素進行運算後再放回棧頂即可。

讀入方面,不做處理,而是放到後面,在運算的同時進行處理。

資料處理。乘10的冪,將字元轉換為十進位制數,放入棧內。

運算——遇到運算子時,取出棧頂元素進行運算。注意:由於棧先進後出的特點,做除法要用第二次取出的元素去除以第一次取出的元素。

最後輸出即可。

#include<iostream>
#include<cstdio>
using namespace std;
long long stk[1000];
int main(){
	long long i=0,now=0;
	char op;
    while((op=getchar())!='@'){
        if(op>='0'&&op<='9') now*=10,now+=op-'0';
        else if(op=='.'){
            stk[++i]=now;
            now=0;
        }
        else if(op=='+'){
            stk[i-1]=stk[i-1]+stk[i];
            stk[i]=0;
            i--;
        }
        else if(op=='-'){
            stk[i-1]=stk[i-1]-stk[i];
            stk[i]=0;
            i--;
        }
        else if(op=='*'){
            stk[i-1]=stk[i-1]*stk[i];
            stk[i]=0;
            i--;
        }
        else if(op=='/'){
            stk[i-1]=stk[i-1]/stk[i];
            stk[i]=0;
            i--;
        }
    }
    cout<<stk[1];
    return 0;
}

補充知識:C++ 自帶模板庫 STL 中有封裝好的 棧。我們可以用 STL 快速的通過這道題。

#include <bits/stdc++.h>
using namespace std;
stack<int> n;//STL裡的棧,宣告格式:stack<資料型別> 棧名稱;
char ch;
int s,x,y;
int main()
{
    while(ch!='@')
    {
        ch=getchar();
        switch(ch)
        {
            case '+':x=n.top();n.pop();y=n.top();n.pop();n.push(x+y);break;
            case '-':x=n.top();n.pop();y=n.top();n.pop();n.push(y-x);break;
            case '*':x=n.top();n.pop();y=n.top();n.pop();n.push(x*y);break;
            case '/':x=n.top();n.pop();y=n.top();n.pop();n.push(y/x);break;
            case '.':n.push(s);s=0;break;
            default :s=s*10+ch-'0';break;
        }
        //n.top():返回棧頂元素
        //n.pop():彈出棧頂元素
        //n.push(x):把x壓入棧
    }
    printf("%d\n",n.top());
    return 0;
}

G(Generating function)

題解

不難發現如果 \(l\leq \lfloor \frac{r}{2}\rfloor+1\),那麼 \(r \% \left(\lfloor\frac{r}{2}\rfloor+1\right)=\lfloor\frac{r-1}{2}\rfloor\)。可以證明,這是最大的可能答案。

同時,讓區間不包含數字 \(\lfloor\frac{r}{2}\rfloor+1\),即 \(l>\lfloor\frac{r}{2}\rfloor+1\)。可以成名最大答案是 \(r \% l = r - l\)

時間複雜度為 \(O(1)\)

#include <bits/stdc++.h>

using namespace std;
#define ll long long

int main() {
    int t;
    std::cin >> t;
    while (t--) {
        ll l, r;
        cin >> l >> r;
        if (r < 2 * l)
            std::cout << r % l << "\n";
        else {
            ll x = (r + 1) / 2;
            std::cout << x - 1 << "\n";
        }
    }
    return 0;
}

本文作者:W-RB,本文遵循 CC BY-NC 協議,轉載請註明原文連結:https://www.cnblogs.com/w-rb/p/15224706.html和作者W-RB,且僅允許在非商業情況下使用