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; }
注意:
- \(ans\) 一定要設定初值或者放到全域性變數。
- 不要少讀入數啊,考場上有好幾位老哥讀入都沒全。
- 開陣列儘量開大,有一位老哥開 \(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,且僅允許在非商業情況下使用