ZZULI-周赛5题解
其实比赛我们三都觉得出的没问题的,但还是出锅了,不止是难度不对口,而且比赛期间A题数据出错了,一直在改数据,到最后才改完。。。
先向各位新生同学说声抱歉吧,没给你们好的周赛体验.如果再来一次,肯定还给你们搞成这样,应该会好好出点有梯度的题目.
本次出题人实力有限,望各位大佬踊跃提出问题和指导,狗头.
A:
题型:水题(出题人原话
思路:小模拟小模拟...就需要注意一下闰年还是非闰年...亿点点小细节
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define debug(x) cout << #x << "=" << x << endl #define debug2(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)。
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; }