2020 乐山师范学院新生程序设计大赛题解
2020 樂山師范學院新生程序設計大賽題解
A 數組求和
中等難度
題目大意:
給定一個數組,執行若干次操作,每次操作可以把兩個相鄰的數變成相反數,求數組最大的和。
解題思路:
這其實是一個思維題,認真思考會發現,最大和,肯定希望數組中的負數是最小的,最好全都是非負數。基于這個思想,會發現,經過若干次操作后,可以讓負數的位置自由移動。例如 n = 5 , ? 5 , 4 , 3 , 2 , 1 n = 5, {-5, 4, 3, 2, 1} n=5,?5,4,3,2,1,第一次移動選擇下標 1,結果就會變成 5 , ? 4 , 3 , 2 , 1 {5, -4, 3, 2, 1} 5,?4,3,2,1,會發現,負數的位置向移動了一,不難發現,在經過 3 3 3 次操作后,數組就會變為 5 , 4 , 3 , 2 , ? 1 {5, 4, 3, 2, -1} 5,4,3,2,?1,此時,數組和就是最大的。
所以這題的做法就很明顯了:
統計負數的個數:
-
如果是偶數個,就可以全部轉換成正整數,因為可以任意移動,就移動成倆倆一對,最后再翻轉過來,所以全都會變成正數。
-
如果是奇數,那必然只會有一個負數,就讓絕對值最小的數變成負數即可。
最后求和判斷下即可:
代碼:
#include <iostream> #include <math.h> using namespace std;const int maxn = 1e5 + 5;int main() {int n;int sum = 0; // 最后的答案和int mi = 10000; // 記錄絕對值最小的int cnt = 0; // 負數的個數cin >> n;for(int i = 0; i < n; ++i) {int a; cin >> a;sum += abs(a); // 直接加上絕對值if(abs(a) < mi)mi = abs(a);if(a < 0)++cnt;}if(cnt % 2 == 1) sum -= 2 * mi; // 如果是奇數個,因為之前加了一個,所以要減去兩倍cout << sum << endl;return 0; }B 超級短的題
困難?反正我是感覺挺困難的。
題目大意:
給定一個數字 n n n,求 n ! n! n! 的最右邊有多少個連續的 0 0 0 。
解題思路:
這有點數學題的味道,要先想清楚數字最右邊的 0 0 0 是怎么來,其實就是 10 10 10 的倍數, 100 100 100 的倍數,以此類推。也就是說一個數有幾個因子是 10 10 10,最右邊就有幾個 0 0 0。所以這題就轉換成怎么求 10 10 10 這個因子的個數。
10 10 10 分解下質因子就是 2 2 2 和 5 5 5 ,也就是找 n ! n! n! 因子里有幾個 2 2 2 和 5 5 5,然后取最小值即可。
這就是一個數學公式:
f ( n ) = ∑ i = 1 ∞ n p i f(n) = \displaystyle\sum_{i=1}^{\infty}\cfrac{n}{p^i} f(n)=i=1∑∞?pin?
其實是求 p p p 的倍數有幾個, p 2 p^2 p2 的倍數有幾個 . . . ... ... 最后累加就是答案
照著這個公式寫代碼即可
其實只用求因子 5 5 5 的個數,因為 5 5 5 的個數是遠遠小于 2 2 2 的個數.
代碼:
#include <iostream> #include <math.h> using namespace std;const int maxn = 1e5 + 5;int main() {int n;cin >> n;int ans = 0;for(int i = 5; i <= n; i *= 5)ans += n / i;cout << ans << endl;return 0; }題目短,代碼也短 _
C 時光倒流
簽到題
題目大意:
給一個 BO5 的比分,看誰能贏。
解題思路:
一個 if 就搞定了
代碼:
#include <iostream> #include <math.h> using namespace std;const int maxn = 1e5 + 5;int main() {int n, m;cin >> n >> m;if(n == 3) cout << "DWG win!\n";else cout << "SN win!\n";return 0; }D 這好像是一道簽到題?
困難。楊會自己出的一道題,和 B 題其實是一樣的,代碼很短,思路有點難
題目大意:
最小化操作次數,使得數組符合題目公式的要求
f ( l , r ) = ∑ i = l r a i ? ∑ i = l r i f(l,r)=\sum^{r}_{i=l}{a_i}-\sum^{r}_{i=l}{i} f(l,r)=i=l∑r?ai??i=l∑r?i
任意的 f ( l , r ) f(l, r) f(l,r) 都是 r ? l + 1 r-l+1 r?l+1 的倍數
解題思路:
這是一個構造體。因為要求數組和最小, 所以 $f(l, r) = r - l +1 $ , 這一步一定要理解,只要這樣,才是倍數關系,并且是最小的。再觀察這個上面的公式,結合剛才結論,當所有的 a i = i + 1 a_i = i+1 ai?=i+1 時,就是符合條件的,因為一一對應相減,貢獻就是 1,有幾個數就有幾個1,就會剛好滿足條件。
所以最終構造的數組其實就是 [ 2 , 3 , 4 , . . . , n , n + 1 ] [2, 3, 4, ..., n, n+1] [2,3,4,...,n,n+1],那最后的問題其實就是最少要多少次,才能把原來的數組構建成目標數組。
這涉及到貪心策略,大致思路就是直接把當前數字減到目標數字,或者減到前一個數字,次數取小累加即可。為什么可以這樣,首先最多就是直接減到目標數字,這是肯定可以的,或者減到和前面一樣,這樣前面減的時候可以一起減,所以后面的就不用算。兩個取最小的即可。
代碼:
#include <iostream> #include <algorithm> using namespace std;const int maxn = 1e6 + 5;long long a[maxn];int main() {int n;long long sum = 0;cin >> n;a[0] = 1;for(int i = 1; i <= n; ++i) {cin >> a[i];// min 和 max 都是 C++ 的函數,傳遞兩個參數,返回最小或者最大值,使用的話要導入頭文件algorithmsum += min(a[i]-i-1, max(0LL, a[i]-a[i-1]));}cout << sum << endl;return 0; }E 追女孩
簽到-簡單難度 (這個方法可以嘗試下_)
題目大意:
給出你和女孩的坐標以及各自的速度,問你能不能追上女生,被追不算
一個坑點就是 當兩人的位置相等時,也是算追上的。
解題思路:
又是一個 if 即可搞定,
代碼:
#include <iostream> using namespace std;int main() {int x, y;int n, m;cin >> x >> y;cin >> n >> m;if(x == y || (x < y && n > m))cout << "Yes\n";elsecout << "No\n";return 0; }F 我怎么會不知道學校的域名?
中等+難度
題目大意:
在給定字符串中,找到符合 l s n u a c m lsnuacm lsnuacm
解題思路:
一般來講,設計到字符串的題目,難度都會高一點,其實實現起來并不難,就是根據題目的規則模擬匹配即可,可以看代碼。
代碼:
#include <iostream> #include <string.h> using namespace std;const int maxn = 1e6 + 5;char s[maxn]; char t[] = "lsnuacm";int main() {cin >> s;int n = strlen(s); // 字符串s的長度int m = strlen(t); // 題目要求 t 的長度// 標志變量, 0表示已經匹配了0個,1表示已經匹配了1個,以此類推int flag = 0;// 答案int cnt = 0;for(int i = 0; i < n; ++i) {// 找 s[i] 是在 t 中的第幾個int j;for(j = 0; j < m; ++j)if(t[j] == s[i])break;// 如果是開頭就是把flag設置為1if(j == 0) flag = 1;else if(j >= m) continue; // 如果不是t中的字符,根據題目規則,需要跳過else if(j == flag) // 如果剛好找的是下一個,匹配數就加一++flag;else flag = 0; // 否則就重置為0if(flag == m) { // 如果已經匹配了m個字符,就表明已經出現了一個,答案加一,并把標志位清空flag = 0;++cnt;}}cout << cnt << endl;return 0; }G 我愛畫沙漏
簡單+難度
題目大意:
我覺的大家都能看懂
解題思路:
非常經典的一個畫圖題,一般分兩次畫,一次畫倒三角,一次畫正三角
代碼:
#include <iostream> using namespace std;int main() {int n;cin >> n;int d = n / 2;// 倒三角for(int i = 0; i <= d; ++i) {for(int j = 0; j < i; ++j)cout << " ";for(int j = 0; j < n-i*2; ++j)cout << "*";cout << endl;}// 正三角for(int i = 1; i <= d; ++i) {for(int j = 0; j < d-i; ++j)cout << " ";for(int j = 0; j < i*2+1; ++j)cout << "*";cout << endl;}return 0; }H 找出所有的重復數字
中等+難度
題目大意:
找出數組中重復的數字,如果沒有或者有負數輸出 ? 1 -1 ?1
解題思路:
這題需要一個技巧,計數技巧,即用數組來統計數字出現的次數。具體看代碼
代碼:
#include <iostream> using namespace std;const int maxn = 1e6 + 5; int cnt[maxn]; int a[maxn];int main() {int n;int flag = 1;cin >> n;for(int i = 0; i < n; ++i) {cin >> a[i];if(a[i] < 0) flag = 0;else ++cnt[a[i]]; // 用數字做下標}if(!flag) { // 出現負數的情況cout << -1 << endl;return 0;}flag = 0;for(int i = 0; i < n; ++i) {if(cnt[i] > 1) {flag = 1; // 說明有重復的數字cout << i << " ";}}if(flag) cout << endl;else cout << -1 << endl;return 0; }I 小學二年級的數學問題
中等難度
題目大意:
就是分數字, 兩邊的個數要一樣,要求差值最小,也就是盡可能均分
解題思路:
這是 2 的冪次形式,所以有 2 1 + 2 2 + 2 3 + . . . + 2 n ? 1 < 2 n 2^1+2^2+2^3+...+2^{n-1} < 2^n 21+22+23+...+2n?1<2n
其實很容易想到,選一個最大的,剩下的全選最小的,差值就是最小的
代碼:
#include <iostream> using namespace std;int main() {int n;cin >> n;int ans = 1 << n; // 左移一位就是乘2,移n位就是乘n個2int i;for(i = 1; i < n/2; ++i)ans += 1 << i;for(; i < n; ++i)ans -= 1 << i;cout << ans << endl;return 0; }J 她生氣了
簡單難度 (get新知識_,蔡隊就是這樣哄女朋友的)
題目大意:
你女朋友現在生氣,說一個詞女朋友的生氣值就會少些,要說多少個詞
解題思路:
就是做一個除法就可以了,余下的也要在說一個
代碼:
#include <iostream> using namespace std;int main() {int n, m;cin >> n >> m;int ans = n / m;if(n % m) ++ans;cout << ans << endl;return 0; }總結
以上是生活随笔為你收集整理的2020 乐山师范学院新生程序设计大赛题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu16.04LTS安装搜狗拼音
- 下一篇: Node.js+express+MySQ