第二次在牛客上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即可。注意要判断高危地区旁边的是不是高危地区,如果是的话,不需要覆盖标记。
#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 合成一个数字即可
#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);
}