A.Little Artem

题意:

给定一个的矩阵,可以在其中的每一格放两种字母,如果一个格子四周有不同字母的格子就称这个点为好点,构造一种方案使得好点的数量多于好点的数量

题解:

令左上角为其余点为即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
void solve()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (i == 1 && j == 1)
                putchar('W');
            else
                putchar('B');
        }
        puts("");
    }
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
}

B.Kind Anton

题意:

数组中的元素构成,并且你可以将数组中的任意元素替换为,该操作能进行任意次,询问数组能否通过变换变成数组

题解:

如果,那么必须存在;如果,那么必须存在。记录两者第一次出现的位置即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int a[maxn], b[maxn];
void solve()
{
    int n;
    scanf("%d", &n);
    int l = 0, r = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        if (a[i] == 1 && !l)
            l = i;
        if (a[i] == -1 && !r)
            r = i;
    }
    bool flag = true;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &b[i]);
        if (b[i] > a[i] && (l >= i || !l))
            flag = false;
        if (b[i] < a[i] && (r >= i || !r))
            flag = false;
    }
    puts(flag ? "YES" : "NO");
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
}

C.Eugene and an array

题意:

统计数组中有几个连续子序列满足:该序列中不存在和为的连续子序列。

题解:

记录每个值上一次出现的位置
前面存在,那么这样的序列只能最后一次取到的下标以后,数量为
同时要与,比较取较大者,因为若,那么序列就可能存在之和为0的情况

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
ll a[maxn];
map<ll, ll> mp;
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    ll sum = 0, res = 0, last = 0;
    mp[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        sum += a[i];
        if (mp[sum])
            last = max(last, mp[sum]);
        res += i - last;
        mp[sum] = i + 1;
    }
    printf("%lld\n", res);
    return 0;
}

D.Challenges in school №41

题意:

给定一个长度为且由字符构成的字符串,每次操作中,你都能选择任意对相邻的,将其变为,询问能否恰好用轮将字符串中的全部移动至左端,全部移动至右端。能则输出每轮要交换的对数和对应的下标,否则输出

题解:

首先要知道如果不限制轮数,那么无论任何字符串最终都能变成要求的,因此每次操作都贪心地将所有能够交换的位置互换,统计最少需要几轮才能完成交换(记为),并统计交换的总次数(记为),如果 那么就可以给出交换方案,因为我们能将某一轮中的操作拆开来,最多能够拆成轮。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 3005;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
vector<int> vec[maxn];
char s[maxn];
int main()
{
    int n, k;
    scanf("%d%d%s", &n, &k, s + 1);
    int cnt = 0, sum = 0;
    while (1)
    {
        bool flag = false;
        cnt++;
        for (int i = 1; i < n; i++)
        {
            if (s[i] == 'R' && s[i + 1] == 'L')
            {
                flag = true;
                vec[cnt].push_back(i);
            }
        }
        for (auto i : vec[cnt])
            swap(s[i], s[i + 1]);
        sum += vec[cnt].size();
        if (!flag)
            break;
    }
    cnt--;
    if (k < cnt || k > sum)
    {
        puts("-1");
        return 0;
    }
    for (int i = 1; i <= cnt; i++)
    {
        while (!vec[i].empty() && k > cnt - i + 1)
        {
            printf("%d %d\n", 1, vec[i].back());
            vec[i].pop_back();
            k--;
        }
        if (!vec[i].empty())
        {
            printf("%d", vec[i].size());
            for (auto it : vec[i])
                printf(" %d", it);
            puts("");
            k--;
        }
    }
    return 0;
}

E.Road to 1600

题意:

构造一个的棋盘,每个格子上的数字是,分别控制两种棋子,国际象棋中的车和后。其中两种棋子的行动路径分别如下:
图片说明
两个棋子分别从出发,按照以下规则进行行走:

  • 到达当前行动路径上权值最小且没有被访问过的格子,将其标记访问;
  • 若当前行动路径上格子都被访问,那么花费1的代价到达一个权值最小且未被访问过的格子;
  • 若所有格子已被访问,那么停止操作。

现在要求构造一种权值方案,使得车消耗的代价小于后所消耗的代价。

题解:

先从规模小的开始考虑,首先,的时候一定无解。因为格子之间总是可达的,无论怎么构造,车和后的代码都为0。
考虑的情况。如下构造可以使得车的代价为,后的代价为


那么的棋盘只需要将的棋盘放在左上角,其余让车和后一起走完即可,的构造如下:
图片说明
图片说明

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
const int b[4][4] = {{0, 0, 0, 0}, {0, 8, 7, 6}, {0, 5, 1, 2}, {0, 4, 9, 3}};
int n, ans[505][505];
int main()
{
    scanf("%d", &n);
    if (n <= 2)
    {
        puts("-1");
        return 0;
    }
    if (n == 3)
    {
        for (int i = 1; i <= 3; i++)
        {
            for (int j = 1; j <= 3; j++)
                printf("%d ", b[i][j]);
            puts("");
        }
        return 0;
    }
    bool flag = ((n - 3) & 1);
    int cnt = 0;
    for (int i = n; i > 3; i--)
    {
        if (flag)
        {
            for (int j = 1; j <= i; ++j)
                ans[i][j] = ++cnt;
            for (int j = i - 1; j >= 1; --j)
                ans[j][i] = ++cnt;
        }
        else
        {
            for (int j = 1; j <= i - 1; ++j)
                ans[j][i] = ++cnt;
            for (int j = i; j >= 1; --j)
                ans[i][j] = ++cnt;
        }
        flag ^= 1;
    }
    swap(ans[1][4], ans[2][4]);
    for (int i = 1; i <= 3; ++i)
        for (int j = 1; j <= 3; ++j)
            ans[i][j] = b[i][j] + cnt;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
            printf("%d ", ans[i][j]);
        puts("");
    }
    return 0;
}

F.Kate and imperfection

题意:

在集合中,对于每个正整数 ,找出一个大小为的子集,使得该子集中两两间最大公因数的最大值最小,给出每个对应的最小值。

题解:

我们考虑如何构造两两间最大公因数的最大值最小的集合,首先肯定是把所有质数先丢进集合里,然后再把与已经在集合内的数的最大公因数的数丢进去,然后是的数……然后注意到,如果我们加入了一个合数,那么他的所有因子必定已经在集合内了,于是加入的这个数字能够产生的最大公因数就是他的最大因子,因此用埃筛维护这个贪心的过程,排序一遍输出即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 3005;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int main()
{
    int n;
    scanf("%d", &n);
    vector<int> ans(n + 1, 1);
    for (int i = 2; i <= n; i++)
        for (int j = i + i; j <= n; j += i)
            ans[j] = i;
    sort(ans.begin(), ans.end());
    for (int i = 2; i <= n; i++)
        printf("%d ", ans[i]);
    puts("");
    return 0;
}