【题解】CSP-J2021第二轮题解
CSP-J2021第二輪題解
T1.分糖果 ? \otimes ?
簡化題目:給定 l , r l,r l,r,求 max ? i = l r ( i m o d n ) \max_{i=l}^{r}(i\bmod n) maxi=lr?(imodn)。
分類討論,根據 ? i n ? \lfloor\frac{i}{n}\rfloor ?ni?? 將整數分組,若 l l l 與 r r r 在同一組中,那么答案為 r m o d n r\bmod n rmodn;否則,答案為 n ? 1 n-1 n?1。具體見下圖。
T2.插入排序 ? \otimes ?
這是一道插入排序的好題,從插入排序的基本思想上出,確實是“更好地理解插入排序”。
插入排序的思想:設原序列為 a i a_i ai?,則插入排序函數 f ( 1 ~ n ) f(1\sim n) f(1~n) 的實現方法就是先處理好 f ( 1 ~ n ? 1 ) f(1\sim n-1) f(1~n?1) 的部分,在將 a n a_n an? 放到合適的位置。過程如下:
a = {[1],4,2,8,5,7} ? \Rarr ? a = {[1,4],2,8,5,7} ? \Rarr ? a = {[1,2,4],8,5,7} ? \Rarr ?
a = {[1,2,4,8],5,7} ? \Rarr ? a = {[1,2,4,5,8],7} ? \Rarr ? a = {[1,2,4,5,7,8]}
故其為 O ( n 2 ) O(n^2) O(n2) 的算法。我們還要結合題目中給的代碼分析一下排序的性質:
這份代碼的排序方式:1.從小到大排列。2.碰到相同的數時,原序列中位置靠前的在前面。
一些基本的東西終于講完了,現在針對這道題講一下啊。首先根據排序方式的第二點,可以得出整道題我們要將一個數的位置和值綁在一起,即一個形如 ( a i , i ) (a_i,i) (ai?,i) 的 pair 。根據 pair 的優先級,在比較整個 pair 時會先比較 a i a_i ai? 的值,再比較 i i i 的值。接下來,在針對操作講一下。從復雜度的角度來看, n ? 5000 , Q ? 200000 n\leqslant5000,Q\leqslant200000 n?5000,Q?200000,每個操作所給的時間并不多。但是,做題的時候,要注意——**看題!**題目中說,操作 1 1 1 的個數不超過 5000,說明操作一的復雜度可以放寬來, O ( n ) O(n) O(n) 剛剛好。由此還可以得知操作二的復雜度就是 O ( 1 ) O(1) O(1)。假如沒有操作一,這題非常簡單,有了操作一之后,維護 p [ i ] p[i] p[i] 表示原序列第 x x x 個數現在所處位置即可。
接下來,這道題的精華就出來了——考慮操作一給結果帶來的變化。根據插入排序的思想,每一個數都慢慢向前面“漂”過去,整個序列的排序是隨著每個數位置的確定而確定。所以,操作一的 O ( n ) O(n) O(n) 做法就是讓被修改的數找到它的位置。過程中,每一次交換都讓兩個的 p p p 值互換。但令人驚奇的是,操作二 O ( n ) O(n) O(n) 竟然能過……
T3.網絡連接 ? \otimes ?
大模擬。關于大模擬的題目,洛谷日報有一期專門講了,還是挺不錯的。
網上雖然有用 sscanf 的方法,但是我不太會,考場上也不一定想得到,這里主要講一下分類討論和模塊化的思想。
模塊化能讓你的代碼少出錯,好調試。這里,我們如果編寫了一個函數 check \text{check} check,那么主函數的代碼將會非常簡短,非常好編寫,重心全部落在 check \text{check} check 函數怎么寫了。題目中給定的要求是形式為 a.b.c.d:e, 0 ? a , b , c , d ? 255 0\leqslant a,b,c,d\leqslant255 0?a,b,c,d?255, 0 ? e ? 65535 0\leqslant e\leqslant 65535 0?e?65535。那么,只需要判斷兩個:1.形式是否合法。2.數字是否符合要求。判斷形式是否合法,主要是判斷 . 的個數和 : 的個數以及它們的順序。這里講幾個容易漏的點:注意形如 .9.63.198:8080 和 89..22.198:8080 等,也就是符號的位置不對。判斷數字是否符合要求比較簡單,不要漏了前導 0 就好了。
這題細節真的是很多,考場上如果不用 sscanf 真的很難 AC,來試一試你能拿多少分吧!
T4.小熊的果籃 ? \otimes ?
這題主要考察 STL 的運用,還看一點運氣。我考試的時候換了好幾個方法,結果都沒出來。正解是用兩個 set,分別記錄蘋果和橘子的位置。每一次先選擇位置最靠前的(min(*st[0].begin(), *st[1].begin())),然后在另一邊二分出下一個塊的位置。這里主要是因為蘋果塊和橘子塊是互相交織的,所以蘋果的位置中第一個大于當前橘子位置的那個位置就是下一個塊的開頭。其他的話,還有一個小技巧,就是在操作之前提前放入 INF,方便判斷蘋果和橘子是不是沒了,最后記得把剩余的水果都輸出一下,具體見代碼。
代碼
T1
#include <bits/stdc++.h> #define int long long using namespace std; inline int read(){int s = 0, w = 1;char ch = getchar();for(; ch < '0' || ch > '9'; w *= ch == '-' ? -1 : 1, ch = getchar());for(; ch >= '0' && ch <= '9'; s = 10 * s + ch - '0', ch = getchar());return s * w; } signed main(){int n = read(), l = read(), r = read(), base = l % n, ans = base;if(l / n != r / n){cout << n - 1 << endl;} else {cout << r % n << endl;}return 0; }T2
#include <bits/stdc++.h> #define int long long using namespace std; inline int read(){int s = 0, w = 1;char ch = getchar();for(; ch < '0' || ch > '9'; w *= ch == '-' ? -1 : 1, ch = getchar());for(; ch >= '0' && ch <= '9'; s = 10 * s + ch - '0', ch = getchar());return s * w; } const int MAXN = 8005; int n, T; pair<int, int> a[MAXN]; signed main(){ // freopen("sort4.in", "r", stdin); // freopen("sort4.out", "w", stdout);n = read(), T = read();for(int i = 1; i <= n; i++){a[i].first = read();a[i].second = i;}sort(a + 1, a + 1 + n);for(int _ = 1, op; _ <= T; _++){ // cout << "Round " << _ << ":" << endl;op = read();if(op == 1){int pos = -1, x = read(), v = read();for(int i = 1; i <= n; i++){if(a[i].second == x){pos = i;break;}}a[pos].first = v;while(pos < n && a[pos] > a[pos + 1]){swap(a[pos], a[pos + 1]);pos++;} // cout << endl; // for(int i = 1; i <= n; i++){ // cout << a[i].first << " " << a[i].second << endl; // }while(pos > 1 && a[pos] < a[pos - 1]){swap(a[pos], a[pos - 1]);pos--;} // cout << endl; // for(int i = 1; i <= n; i++){ // cout << a[i].first << " " << a[i].second << endl; // }} else if (op == 2){int x = read();for(int i = 1; i <= n; i++){if(a[i].second == x) {cout << i << endl;break;}} // cout << endl; // for(int i = 1; i <= n; i++){ // cout << a[i].first << " " << a[i].second << endl; // }}}return 0; }T3
#include <bits/stdc++.h> #define int long long using namespace std; inline int read(){int s = 0, w = 1;char ch = getchar();for(; ch < '0' || ch > '9'; w *= ch == '-' ? -1 : 1, ch = getchar());for(; ch >= '0' && ch <= '9'; s = 10 * s + ch - '0', ch = getchar());return s * w; } const int MAXN = 1005; string cl[MAXN]; int check_int(string s){if(s.size() == 0) return -1;if(s.size() == 1) return s[0] - '0';if(s[0] == '0') return -1;int res = 0;for(int i = 0; i < s.size(); i++){res = res * 10 + s[i] - '0';}return res; } bool check(string s){int cntdot = 0, cntdots = 0;for(int i = 0; i < s.size(); i++){cntdot += (s[i] == '.');cntdots += (s[i] == ':');}if(cntdot != 3 || cntdots != 1) return false;int l = 0;bool flag = false;if(s[0] == '.') return false;for(int i = 1, tmp; i < s.size(); i++){if(s[i] == '.' || s[i] == ':'){if(s[i - 1] == '.' || s[i - 1] == ':') return false;if(s[i] == ':') flag = true;if(flag && s[i] == '.') return false;tmp = check_int(s.substr(l, i - l));if(tmp == -1) return false;if(tmp >= 256) return false;l = i + 1;}}int tmp = check_int(s.substr(l, s.size() - l + 1));if(tmp < 0 || tmp > 65535) return false;return true; } signed main(){ // freopen("P7911_14.in", "r", stdin); // freopen("P7911_14.user", "w", stdout);int n = read(), tot = 0;string tmp;for(int i = 1; i <= n; i++){getline(cin, tmp);string s = tmp.substr(7, tmp.size() - 7);if(check(s) == false){cout << "ERR" << endl;continue;}if(tmp.substr(0, 6) == "Server"){bool flag = true;for(int j = 1; j < i; j++){if(cl[j] == s){cout << "FAIL" << endl;flag = false;break;}}if(flag){cout << "OK" << endl;cl[i] = s;}} else {bool flag = true;for(int j = 1; j < i; j++){if(cl[j] == s){cout << j << endl;flag = false;break; }}if(flag) cout << "FAIL" << endl;}}return 0; }T4
#include <bits/stdc++.h> #define int long long using namespace std; inline int read(){int s = 0, w = 1;char ch = getchar();for(; ch < '0' || ch > '9'; w *= ch == '-' ? -1 : 1, ch = getchar());for(; ch >= '0' && ch <= '9'; s = 10 * s + ch - '0', ch = getchar());return s * w; } set<int> st[2]; signed main(){int n = read();for(int i = 1; i <= n; i++){st[read()].insert(i);}for(int i = 0; i < 2; i++){for(set<int>::iterator it = st[i].begin(); it != st[i].end(); it++){cout << *it << " ";}cout << endl;}while(!st[0].empty() && !st[1].empty()){set<pair<int, int> > out;for(int d = 0, lst; d < 2; d++){lst = *st[d].begin();out.insert(make_pair(lst, d));for(set<int>::iterator it = ++st[d].begin(); it != st[d].end(); it++){if(lst + 1 < *it) out.insert(make_pair(*it, d)); // cout << lst << " " << *it << endl;lst = *it;}}for(set<pair<int, int> >::iterator it = out.begin(); it != out.end(); it++){cout << it->first << " ";st[it->second].erase(it->first);}cout << endl;}return 0; }后記
我整理了一下 CSP-J2019 ~ 2021 \text{CSP-J2019}\sim\text{2021} CSP-J2019~2021 的題目難度(以洛谷為主):
| 2019 \text{2019} 2019 | 入門 \textbf{\textcolor{#FFFFFF}{\colorbox{#FE4C61}{入門}}} 入門? | 普及- \textbf{\textcolor{#FFFFFF}{\colorbox{#F39C11}{普及-}}} 普及-? | 普及 \textbf{\textcolor{#FFFFFF}{\colorbox{#52C41A}{普及}}} 普及? | 普及 \textbf{\textcolor{#FFFFFF}{\colorbox{#52C41A}{普及}}} 普及? |
| 2020 \text{2020} 2020 | 入門 \textbf{\textcolor{#FFFFFF}{\colorbox{#FE4C61}{入門}}} 入門? | 普及- \textbf{\textcolor{#FFFFFF}{\colorbox{#F39C11}{普及-}}} 普及-? | 普及 \textbf{\textcolor{#FFFFFF}{\colorbox{#FFC116}{普及}}} 普及? | 普及 \textbf{\textcolor{#FFFFFF}{\colorbox{#52C41A}{普及}}} 普及? |
| 2021 \text{2021} 2021 | 入門 \textbf{\textcolor{#FFFFFF}{\colorbox{#FE4C61}{入門}}} 入門? | 普及- \textbf{\textcolor{#FFFFFF}{\colorbox{#F39C11}{普及-}}} 普及-? | 普及 \textbf{\textcolor{#FFFFFF}{\colorbox{#FFC116}{普及}}} 普及? | 普及 \textbf{\textcolor{#FFFFFF}{\colorbox{#FFC116}{普及}}} 普及? |
可以發現題目是越來越簡單了,但是越簡單的題目越是要得分,這樣子才有機會拿到省一。
總結
以上是生活随笔為你收集整理的【题解】CSP-J2021第二轮题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 非全研究生业余研究:利用十一假期训练了室
- 下一篇: 2020总结 2021规划