第二次在牛客上AK(可能是数据比较水?被我卡过去了?)
总的来说感觉题目原题偏多?没有特别难的防AK题好评
A、Race
题意:给出两个人的速度,和赛道总长度,如果小明超过小红一定的距离,需要等待T秒,问谁先到终点
模拟,只在整数秒判断状态即可,注意只需要小明等待小红,不需要双向等待。
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; int main() { int v1, v2, t, s, l; sc("%d%d%d%d%d", &v1, &v2, &t, &s, &l); double a = 0, b = 0; int time = 0; int time1 = 0, time2 = 0; while (a < l && b < l) { a += v1; b += v2; time++; if (a >= l || b >= l) break; if (a >= b + t) { for (int i = 0; i < s; i++) { b += v2; time++; if (b >= l) goto qwe; } } } qwe:; if (a >= l && b >= l) pr("Tie %d\n", time); else if (a >= l) pr("Ming %d\n", time); else pr("Hong %d\n", time); }B、Min Value
题意:给一个数组,取两个数字,要求两个数字的和的绝对值最小,第二要求下标之和最小
对于每个数字,我们只需要找到最接近他的相反数的数字即可,使用set即可解决
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; map<int, int>mp; int a[200005]; int main() { int n; sc("%d", &n); for (int i = 1; i <= n; i++) { sc("%lld", &a[i]); if (!mp.count(a[i])) mp[a[i]] = i; } int ans = 1e9 + 7, ans1 = 0; set<int>s; s.insert(a[1]); for (int i = 2; i <= n; i++) { auto it = s.lower_bound(-a[i]); if (it != s.end()) { int num = *it; if (ans > abs(num + a[i])) { ans = abs(num + a[i]); ans1 = i + mp[num]; } else if (ans == abs(num + a[i])) { ans1 = min(ans1, i + mp[num]); } } if (it != s.begin()) { it--; int num = *it; if (ans > abs(num + a[i])) { ans = abs(num + a[i]); ans1 = i + mp[num]; } else if (ans == abs(num + a[i])) { ans1 = min(ans1, i + mp[num]); } } s.insert(a[i]); } pr("%d %d\n", ans, ans1); }C、Coronavirus
题意:n*m的图,高危地区旁边8个位置不能走,求能否从S走到E,最短步数
简单bfs,先把所有高危地区的旁边标记,然后直接bfs即可。注意要判断高危地区旁边的是不是高危地区,如果是的话,不需要覆盖标记。
简单bfs,先把所有高危地区的旁边标记,然后直接bfs即可。注意要判断高危地区旁边的是不是高危地区,如果是的话,不需要覆盖标记。
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; char s[55][55]; int dir[4][2] = { 1,0,0,1,-1,0,0,-1 }; struct node { int first; int second; int step; }; int book[55][55]; int main() { int n, m; sc("%d%d", &n, &m); queue<node>q; for (int i = 1; i <= n; i++) sc("%s", s[i] + 1); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (s[i][j] == 'S') { q.push(node{ i,j,0 }); book[i][j] = true; } if (s[i][j] == '*') { for (int q = i - 1; q <= i + 1; q++) { for (int w = j - 1; w <= j + 1; w++) { if (s[q][w] == '.') s[q][w] = '@'; if (s[q][w] == 'E') { pr("Impossible\n"); return 0; } } } } } } while (!q.empty()) { node t = q.front(); if (s[t.first][t.second] == 'E') { pr("%d\n", t.step); return 0; } q.pop(); for (int k = 0; k < 4; k++) { int tx = t.first + dir[k][0]; int ty = t.second + dir[k][1]; if (tx<1 || tx>n || ty<1 || ty>m) continue; if (book[tx][ty] == true || s[tx][ty] == '*' || s[tx][ty] == '@') continue; book[tx][ty] = true; q.push(node{ tx,ty,t.step + 1 }); } } pr("Impossible\n"); }D、Array
题意:n个数字异或值已知,和已知,求最少多少个数字满足题目所述的条件
CF原题的简单版?可以证明3个数字一定足够 a, (b-a)/2, (b-a)/2
《Codeforces Round #628 (Div. 2) D》
给两个数字,a,b ,一些数字异或等于a,求和等于b,问数字至有多少个并输出
若a>b,显然无解,然后由于题意特判0 0 和a==b的情况。
剩下的情况,由于异或的特性,a,b的奇偶性相同,所以判断不行的,就剩下 a, (b-a)/2, (b-a)/2
然后判断一下 a 能不能和 (b-a)/2 合成一个数字即可
若a>b,显然无解,然后由于题意特判0 0 和a==b的情况。
剩下的情况,由于异或的特性,a,b的奇偶性相同,所以判断不行的,就剩下 a, (b-a)/2, (b-a)/2
然后判断一下 a 能不能和 (b-a)/2 合成一个数字即可
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; int main() { ll a, b; while (sc("%lld%lld", &a, &b) > 0) { if (a > b) pr("-1\n"); else if (a == 0 && b == 0) pr("0\n"); else if (a == b) pr("1\n"); else { ll x = (b - a) / 2; if ((b - a) & 1) pr("-1\n"); else if ((x & a) == 0) pr("2\n"); else pr("3\n"); } } }E、Prize
题意:给n个数字,给m个匹配长度,每个匹配位置可能有多个数字满足匹配要求,问有多少个完全匹配题目给定的m个条件
暴力复杂度大概1.6e9,过不去,(然后想起了这学期讲了个从后往前匹配可能会更快?),然后尝试一下,过了?不知道能不能证明复杂度,不过我猜是数据比较弱让我卡过去了?(运行时间: 219 ms)
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; const int MAXN = 2e6 + 5; char s[MAXN]; bool a[805][11]; int main() { int n, m; sc("%d%d", &n, &m); sc("%s", s + 1); for (int i = 1; i <= m; i++) { int t; sc("%d", &t); while (t--) { int tt; sc("%d", &tt); a[i][tt] = true; } } int cnt = 0; for (int i = n; i >= m; i--) { for (int j = i, k = m; j >= i - m + 1 && k >= 1; j--, k--) { if (a[k][s[j] - '0'] == false) goto qwe; } cnt++; i = i + 1 - m; qwe:; } if (cnt == 0) pr("Failed to win the prize"); else pr("%d", cnt); }F、Animal Protection
题意:求不包含给定点的,构成的不同矩形的数量。
大概两年前网络赛的原题?暴力枚举,复杂度大概在 O(n*m*min(n,m))
本题大概在 1e9/2=4e8,感觉在超时的边缘试探,然后过了,感谢出题人放过
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; char s[1005]; int e[1005][1005], up[1005]; const ll mod = 1e9 + 7; int main() { int t, n, m, k, a, b; ll ans = 0; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { sc("%s", s + 1); for (int j = 1; j <= m; j++) { if (s[j] == 'X') e[i][j] = 1; } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) if (e[i][j]) up[j] = i; for (int j = 1; j <= m; j++) { ll temp = LLONG_MAX; for (int k = j; k >= 1; k--) { temp = min(temp, (ll)(i - up[k])); ans = (ans + temp); } } } printf("%lld\n", ans % mod); }G、XOR
题意:从1-n里面选两个数字异或最大值
注意到我们只要取最高位为1其他为0 和 最高位为0其他为1的两个数字即可满足从最高位开始全为1,最大。
由于两个数字必须不同,所以注意特判0
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; int main() { ll n, ans = 0; sc("%lld", &n); if (n==1) { pr("0"); return 0; } for (ll i = 1; true; i = i * 2) { if (i <= n) ans += i; else break; } pr("%lld\n", ans); }H、Maze
题意:n*m的图,图中只包含+,-两个符号,+只能走到-,-只能走到+,q次询问,每个询问给出一个点,问这个点能到达的点的数量
显然,一个点能走到的点的对应查询答案是一样的,所以我们对图进行染色并且记录每个颜色的数量即可。
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf #define Pair pair<int,int> using namespace std; const int MAXN = 3005; char ss[MAXN]; int s[MAXN][MAXN]; bool book[MAXN][MAXN]; int color[MAXN][MAXN]; int ans[MAXN * MAXN]; int dir[4][2] = { 1,0,0,1,-1,0,0,-1 }; int n, m, k; void dfs(int x, int y, int cnt) { queue<Pair>q; q.push(Pair{ x,y }); while (!q.empty()) { Pair t = q.front(); q.pop(); for (int k = 0; k < 4; k++) { int tx = t.first + dir[k][0]; int ty = t.second + dir[k][1]; if (tx<1 || tx>n || ty<1 || ty>m) continue; if (book[tx][ty] == true || s[tx][ty] == s[t.first][t.second]) continue; book[tx][ty] = true; color[tx][ty] = cnt; ans[cnt]++; q.push(Pair{ tx,ty }); } } } int main() { sc("%d%d%d", &n, &m, &k); for (int i = 1; i <= n; i++) { sc("%s", ss + 1); for (int j = 1; j <= m; j++) s[i][j] = (ss[j] == '+' ? 1 : 0); } int cnt = 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (book[i][j] == false) { book[i][j] = true; color[i][j] = cnt; ans[cnt]++; dfs(i, j, cnt); cnt++; } } while (k--) { int x, y; sc("%d%d", &x, &y); pr("%d\n", ans[color[x][y]]); } }I、Prime
题意:求区间质数个数
埃筛或者欧拉筛都可通过此题
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; const int MAXN = 1e7 + 5; bool vis[MAXN]; int prime[MAXN]; int cnt = 0; int sub[MAXN]; void Eluer() { for (int i = 2; i < MAXN; i++) { if (vis[i] == false) { prime[cnt++] = i; } for (int j = 0; j < cnt && i * prime[j] < MAXN; j++) { vis[i * prime[j]] = true; if (i % prime[j] == 0) break; } } sub[1] = 0; for (int i = 2; i < MAXN; i++) sub[i] = sub[i - 1] + (vis[i] == false ? 1 : 0); } int main() { Eluer(); int T; sc("%d", &T); while (T--) { int a, b; sc("%d%d", &a, &b); pr("%d\n", sub[b] - sub[a - 1]); } }J、Compare
题意:比较两个最多1000位数字的大小
字符串或者上JAVA大数
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; char s1[100005], s2[100005]; int main() { sc("%s%s", s1, s2); int len1 = strlen(s1); int len2 = strlen(s2); if (len1 > len2) pr(">"); else if (len1 < len2) pr("<"); else { for (int i = 0; i < len1; i++) { if (s1[i] < s2[i]) { pr("<"); return 0; } if (s1[i] > s2[i]) { pr(">"); return 0; } } pr("="); } }K、Walk
题意:n*m的图,从左上角走到右下角,步数最少的情况有多少种
欧拉计划原题?最少要走n+m-2步,假设这些步数都走右边,那么我们要选择其中的m-1步向下走才能到达右下角,所以答案是C(n+m-2,m-1)
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; const int MAXN = 2e6 + 5; const ll mod = 1e9 + 7; ll invi[MAXN], fac[MAXN], inv[MAXN]; void init() { invi[0] = invi[1] = 1; fac[0] = 1; inv[0] = 1; for (int i = 2; i < MAXN; i++) invi[i] = invi[mod % i] * (ll)(mod - mod / i) % mod; for (int i = 1; i < MAXN; i++) { fac[i] = fac[i - 1] * i % mod; inv[i] = invi[i] * inv[i - 1] % mod; } } ll C(ll n, ll m) { ll ans = fac[n] * inv[m] % mod * inv[n - m] % mod; return ans; } int main() { init(); int T; sc("%d", &T); while (T--) { ll n, m; sc("%lld%lld", &n, &m); n--, m--; ll ans = C(n + m, m); pr("%lld\n", ans); } }L、Defeat the monster
题意:有n个人,选择最大值与最小值不超过5的最大人数
这个题目怎么长的有点眼熟?这不是我出的牛客小白赛嘛。滑动窗口、二分都可解决这个问题,可以参考 牛客小白月赛24B https://ac.nowcoder.com/acm/contest/5158/B
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; ll a[200005]; int main() { int n; sc("%d", &n); for (int i = 1; i <= n; i++) sc("%lld", &a[i]); sort(a + 1, a + 1 + n); int ans = 0, st = 1, ed = 0; while (ed < n) { ed++; while (a[ed] > a[st] + 5) st++; ans = max(ans, ed - st + 1); } pr("%d\n", ans); }