ZZULI-周賽5題解
其實比賽我們三都覺得出的沒問題的,但還是出鍋了,不止是難度不對口,而且比賽期間A題資料出錯了,一直在改資料,到最後才改完。。。
先向各位新生同學說聲抱歉吧,沒給你們好的周賽體驗.如果再來一次,肯定還給你們搞成這樣,應該會好好出點有梯度的題目.
本次出題人實力有限,望各位大佬踴躍提出問題和指導,狗頭.
A:
題型:水題(出題人原話
思路:小模擬小模擬...就需要注意一下閏年還是非閏年...億點點小細節
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define debug(x) cout << #x << "=" << x << endl #definedebug2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl // *(ve._M_impl._M_start)@(ve.size()) char *p[] = {"NO", "YES"}; const int mod = 1e9 + 7; const int maxn = 1e5 + 7; ll day_run[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; ll day_pin[]= {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; ll pan(ll y) { if (y % 4 == 0 && y % 100 != 0) { return 1; } else if (y % 400 == 0) { return 1; } return 0; } void add(ll &y, ll &m, ll &d) { d++; if (pan(y)) { if (day_run[m] < d) { m++; d = 1; } if (m > 12) { y++; m = 1; } } else { if (day_pin[m] < d) { m++; d = 1; } if (m > 12) { y++; m = 1; } } } ll hanyou(ll &y, ll &m, ll &d, ll &y2, ll &m2, ll &d2) { ll s = y * 10000 + m * 100 + d; ll s2 = y2 * 10000 + m2 * 100 + d2; if (s <= s2) { return 1; } return 0; } int main() { ll y, m, d, n, i, a, b, c, sh = 14, lo = 66; ll ys, ms, ds, yl, ml, dl; scanf("%lld-%lld-%lld", &y, &m, &d); ys = yl = y; ms = ml = m; ds = dl = d; for (i = 1; i < sh; i++) { add(ys, ms, ds); } for (i = 1; i < lo; i++) { add(yl, ml, dl); } scanf("%lld", &n); for (i = 0; i < n; i++) { scanf("%lld-%lld-%lld", &a, &b, &c); if (hanyou(a, b, c, ys, ms, ds)) { add(ys, ms, ds); } if (hanyou(a, b, c, yl, ml, dl)) { add(yl, ml, dl); } } printf("%lld-%lld-%lld\n", ys, ms, ds); printf("%lld-%lld-%lld\n", yl, ml, dl); return 0; }
B:略
C:
題型:思維題...
思路:對於陣列中第 i 個元素考慮計算次數,當前元素只被前 i - 1 個元素乘一遍(記得取餘操作,還有long long避免資料溢位).
前後綴都可以做到.
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 100; typedef long long ll; ll a[maxn],sum[maxn]; const int mod = 1e9 + 7; int main(){ int n;cin >> n; for(int i = 1;i <= n;i++) { cin >> a[i]; sum[i] = sum[i - 1] + a[i]; sum[i] %= mod; } ll ans = 0; for(int i = 2;i <= n;i++){ ans = (ans + a[i] * sum[i-1]) % mod; } cout << ans % mod<< endl; return 0; }
D:
題型:思維題...(題面可能沒解釋清楚...我的鍋)
思路:對於 i ( 0 < i <= n) 來說,A[ i ]就是被引用 i 次的文章個數,那麼可以考慮從 i = n 迴圈到i == 0.維護當前 i ~ n 之間的和 sum,當滿足 sum >= i 就是題目要求的答案,輸出當前 i 即可.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 100; int n, a[maxn]; int main() { scanf("%d", &n); for (int i = 1; i <= n + 1; i++) scanf("%d", &a[i]); ll sum = a[n + 1]; for (int i = n; i >= 0; i--) { if (sum >= i) { printf("%d\n", i); break; } sum += a[i]; } return 0; }
E:
題型:數學知識...
思路:
設 x <= y,當 x == y 時,原式出成立,所以x < y。
因為x < y + GCD ( x , y ) < y,所以 x + y + GCD ( x , y ) < 3y,又因為 x + y + GCD ( x , y ) > y 且 LCM ( x , y ) 是 y 的整數倍,所以 x < y + GCD ( x , y ) = 2y,且 LCM ( x , y ) = 2y。
因為 x * y =GCD ( x , y ) * LCM ( x , y ) ,所以 x * y = 2y * GCD ( x , y ),得到 GCD ( x , y ) = x / 2;帶回原式得 x + y + x / 2 = 2y,解得 x = 2 / 3y或者 y = 3/2x。
由以上結論得,對於每個偶數x,滿足 x + y +GCD ( x , y ) = LCM ( x , y ) 且大於 x 的 y 有且只有一個,即 y = 3 / 2x。而奇數則不存在這樣的y。
所以將選出來的數從小到大排序,去重,一定滿足 bi = 2 / 3b( i + 1) (1 <= i <= k)。
#include<stdio.h> #include<math.h> #include<stdlib.h> #define N 200000 int n,a[N],ans = -1,b[N]; int main(void){ scanf("%d",&n); for(int i = 0;i<n;i++){ scanf("%d",&a[i]); b[a[i]]++; //通過b陣列來統計a[i]的個數 } for(int i = 0;i < n;i++){ //氣泡排序 for(int j = 0;j <n-1-i;j++){ if(a[j]>a[j+1]){ int temp = a[j]; a[j] =a[j+1]; a[j+1] =temp; } } } for(int i = 0;i<n;i++){ int temp = a[i],sum = 0; while(b[a[temp]]){ //從陣列中取出一個數,然後在while訓中改變數值; sum +=temp*b[temp]; //當該數存在時,進行迴圈,sum統計存在的值,該值要乘上其個數 if(temp%2==0) //更加推論,如果該數是偶數,則尋找對應的y值, temp = temp/2*3; else break; } if(sum>ans) //獲得最大的累加之積 ans =sum; } printf("%d\n",ans); return 0; }
F:
題型:模擬...
思路:直接模擬接水過程,剛開始時讓m個水龍頭都開著,m個同學都在接水,一旦有一個同學接完了,下一個同學就立刻來這個水龍頭接水。
#include<stdio.h> #include<math.h> #include<stdlib.h> #define N 200000 int a[N],b[N],n,m,t,ans; int main(void){ scanf("%d %d",&n,&m); for(int i = 1;i<=n;i++) scanf("%d",&a[i]); t = m + 1; //記錄等待接水的隊伍中的第一個學生的編號 while(t<=n+m){ for(int i = 1;i<=m;i++){ //列舉m個水龍頭,在一次迴圈結束後, //接水的m個同學的要接的水的量減一 a[i]--; if(!a[i]){ //如果有個同學接完水了,下一個同學補上 a[i] =a[t]; t++; } } ans++; //當for迴圈結束後,表示模擬的時間為1秒,ans加一 } printf("%d\n",ans); return 0; }
G:
題型:模擬...
思路:直接根據題意模擬,標記小K學長和女神吃到第幾個糖果,以及他們所用的時間,如果女神當前的時間小於等於小K學長的時間,則女神開始吃下一個,否則小K學長開始吃下一個。
#include <stdio.h> #include <math.h> #include <stdlib.h> #define N 100000 int n, a[N], l, r, sum1, sum2; int main(void) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); l = 1, r = n; //l代表女神吃到糖果的位置,r代表小K遲到的糖果的位置 while (l <= r) { if (sum1 <= sum2) { //sum1代表女神所用的時間,sum2代表小K學長所用的時間, sum1 +=a[l++]; //如果sum1<=sum2,則女神開始吃下一個糖果 sum1 += a[l++]; } else { sum2 += a[r--]; } } printf("%d %d", l - 1, n - l + 1); //l-1表示女神吃到的糖果的位置,因為女神是從前往後開始 //吃的,所以l-1也表示女神吃了幾個,那麼剩下的就代表小K學長吃的糖果數。 return 0; }
H:
題型:大模擬(手動狗頭
思路:直接模擬呀!!!(來自隊友大佬的原話
#include <bits/stdc++.h> using namespace std; typedef long long ll; char *p[] = {"NO", "YES"}; const int mod = 1e9 + 7; const int maxn = 1e5 + 7; ll jiafen(ll liansheng, ll jili[]) { if (liansheng > 5) { liansheng = 5; } return jili[liansheng]; } char *pqwe[] = {"", "Bronze", "Silver", "Gold", "Platinum", "Diamond", "Star", "the strongest king"}; int main() { char a[2000]; while (~scanf("%s", a)) { ll liststar[] = {0, 3, 3, 4, 4, 5, 5, 200}; ll listduan[] = {0, 3, 3, 4, 5, 5, 5, 1}; ll jili[] = {0, 0, 8, 13, 18, 23}; ll le = 1, le2 = 1, star = 0, i, len, integral = 0, card = 0; ll jifenwin = 10, liansheng; len = strlen(a); liansheng = 0; for (i = 0; i < len; i++) { if (a[i] == 'W') { liansheng++; star++; integral += jifenwin; integral += jiafen(liansheng, jili); if (integral >= 350) { integral -= 350; star++; } if (star > liststar[le]) { star -= liststar[le]; le2++; if (le2 > listduan[le]) { le2 -= listduan[le]; le++; card += 2; } } } else { liansheng = 0; if (le == 1) { continue; } else if (le == 2 && le2 == 1 && star == 0) { continue; } if (card) { card--; } else if (integral >= 150) { integral = 0; } else { star--; if (star < 0) { le2--; if (le2 < 1) { le--; le2 = listduan[le]; } star = liststar[le] - 1; } } } } if (le != 7) printf("%s-%lld-%lld\n", pqwe[le], le2, star); else printf("%s-%lld\n", pqwe[le], star); } return 0; }
I:
題型:DP...(想當防AK題的
思路:對於第二個答案,就是陣列中最長上升子序列的長度,因為對於第 i 個元素,如果沒有比前 i - 1 個元素小,那麼必然需要再多一個導彈系統來放出更高的防空導彈來防衛,即就陣列中最長上升子序列的長度.
對於第一個答案,就是反向陣列最長非下降子序列的長度 .
哈?你問我什麼事最長上升子序列?建議百度,我太菜了...
// 輸入可以使用簡單的 while(scanf("%d",&a[i]) != EOF)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; int dp[100005]; int main(){ string s;getline(cin,s); stringstream ss; ss << s; vector<int> q; int x; while(ss >> x) q.push_back(x);
// 輸入可以使用簡單的 while(scanf("%d",&a[i]) != EOF) int n = q.size(); for(int i = 0;i <= n;i++) dp[i] = inf; for(int i = 0;i < q.size();i++){ *lower_bound(dp,dp+n,q[i]) = q[i]; } int cnt = lower_bound(dp,dp+n,inf) - dp; reverse(q.begin(),q.end()); for(int i = 0;i <= n;i++) dp[i] = inf; for(int i = 0;i < q.size();i++){ *upper_bound(dp,dp+n,q[i]) = q[i]; } cout << lower_bound(dp,dp+n,inf) - dp << endl; cout << cnt <<endl; return 0; }