Codeforces Round #533(div.2)解题报告

Codeforces Round #533(div.2)解题报告

A. Salem and Sticks

题意:

  • 给定一个序列长度为n,你可以对每个数字加或者减。
  • 每次加减的代价是数字大小变化之差。
  • 序列中一个数字如果和一个数字t绝对值之差小于等于一,认为这个数字是好的。
  • 请你给出一个t,并求出使序列所有数字变化后是好的最小代价。

  • 数据范围\(n\leq 1000,a_i\leq 100\)

思路:

  • 因为数据范围比较小,所以直接枚举\(t\),每次线性判断结果,取最小值。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 10;
int n, a[maxn];
int main()
{
    scanf("%d", &n);
    int l = 0x3f3f3f3f, r = -1;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        l = min(l, a[i]);
        r = max(r, a[i]);
    }
    int ans_t = 0;
    int ans_s = 0x3f3f3f3f;
    for(int t = l; t <= r; t++)
    {
        int sum = 0;
        for(int i = 1; i <= n; i++)
        {
            int x = a[i];
            if(abs(x-t) <= 1) continue;
            if(x >= t) sum += x - (t+1);
            else sum += (t-1) - x;
        }
        if(sum < ans_s)
        {
            ans_t = t;
            ans_s = sum;
        }
    }
    cout << ans_t << " " << ans_s << endl;
    return 0;
}

B. Zuhair and Strings

题意:

  • 给一串长度为n的字符串,求长度为k的相同单种字母组成的子串的最大数量。

思路:

  • 暴力判断就行。因为只有一个字符,也用不上什么算法。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n, k;
string str;
int a[30];
bool cmp(int a, int b){
    return a > b;
}
int main()
{
    cin >> n >> k;
    cin >> str;
    int res = 1;
    for(int i = 0; i < n; i++)
    {
        if(k == 1) a[str[i]-'a']++;
        else
        {
            //连续出现的字符
            if(str[i] == str[i+1]) res ++;
            else res = 1;
            //出现了k次
            if(res == k)
            {
                a[str[i]-'a']++;
                res = 1; i += 1; //跳过i+1这个字符
            }
        }
    } int ans = 0;
    for(int i = 0; i <= 28; i++) ans = max(ans, a[i]);
    cout << ans << endl;
    return 0;
}

C. Ayoub and Lost Array

题意:

  • 一个长度为n的序列,每个数字在\([l,r]\)区间。
  • 序列数字的和是3的倍数。
  • 问有多少序列满足条件。
  • 对结果取模\(10^9+7\)

思路:

  • 如果要考虑数字的话,那也太麻烦了。

  • 数的总和只有三种关系,\(sum\ mod\ 3=1,2,0\),可以从这个方向考虑。
  • \(f(i,0/1/2)\)表示长度为\(i\)的序列中,总和取模3为0,1,2的序列的数量。
  • 先处理一下区间模3余0,1,2的数量,然后推一推公式就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 10;
int n, l, r, m0, m1, m2;
ll f[maxn][5];

void init()
{
    m0 += r/3, m1 += r/3, m2 += r/3;
    m0 -= (l-1)/3, m1 -= (l-1)/3;
    m2 -= (l-1)/3;
    int t = r%3;
    if(t == 1) m1++;
    else if(t == 2) m1++, m2++;
    t = (l-1) % 3;
    if(t == 1) m1--;
    else if(t == 2) m1--, m2--;
}

int main()
{
    cin >> n >> l >> r;
    init();
    f[1][0] = m0, f[1][1] = m1, f[1][2] = m2;
    for(int i = 2; i <= n; i++)
    {
        f[i][0] += (f[i-1][0]*m0)%mod; f[i][0] %= mod;
        f[i][0] += (f[i-1][1]*m2)%mod; f[i][0] %= mod;
        f[i][0] += (f[i-1][2]*m1)%mod; f[i][0] %= mod;

        f[i][1] += (f[i-1][1]*m0)%mod; f[i][1] %= mod;
        f[i][1] += (f[i-1][2]*m2)%mod; f[i][1] %= mod;
        f[i][1] += (f[i-1][0]*m1)%mod; f[i][1] %= mod;

        f[i][2] += (f[i-1][1]*m1)%mod; f[i][2] %= mod;
        f[i][2] += (f[i-1][2]*m0)%mod; f[i][2] %= mod;
        f[i][2] += (f[i-1][0]*m2)%mod; f[i][2] %= mod;
    }
    cout << f[n][0] << endl;
    return 0;
}

D. Kilani and the Game

题意:

  • 几个人在玩一个游戏,首先有一个二维棋盘。
  • 1,2,3,...号玩家轮流移动,每次可以从已有的地盘开始向上下左右扩张占领,扩张的速度是\(s(i)\)
  • 不能占领被其他玩家占领或者被锁住的地盘,当没有玩家能够移动的时候,游戏结束。
  • 问最终这几名玩家每人占领多少地盘?

思路:

  • 首先,对于每个玩家扩张而言,就是bfs。
  • 每个玩家扩张的速度是\(s(i)\),其实意思就是bfs搜的深度是\(s(i)\)
  • 我们有\(p\)个玩家,\(p\leq 9\),其实可以直接维护\(p\)个队列来进行bfs。
  • 我们知道bfs具有两段性和单调性。
    • 两段性:bfs队列中只有两层节点。
    • 单调性:bfs搜完一层才会搜下一层。
  • 所以我们可以借助这两个性质完成对深度的控制。
  • 同时当没有人能够扩展节点后,退出游戏,输出结果。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
int n, m, p;
int s[15];
int a[maxn][maxn];
char t[maxn][maxn];
struct Node{
    int x, y, step;
};
queue<Node> q[15], qt;

int dx[5] = {0, -1, 1, 0, 0};
int dy[5] = {0, 0, 0, -1, 1};
int ans[12];

void bfs(int u)
{
    while(qt.size())
    {
        Node tmp = qt.front(); qt.pop();
        if(tmp.step == 0) q[u].push(tmp);
        else
        {
            for(int i = 1, x, y; i <= 4; i++)
            {
                x = tmp.x + dx[i];
                y = tmp.y + dy[i];
                if( (x < 1 || x > n || y < 1 || y > m) || a[x][y] != 0 || t[x][y] != '.') continue;
                    a[x][y] = u;
                qt.push(Node{x, y, tmp.step-1});
            }
        }
    }
}

bool solve(int x)
{
    while(q[x].size())
    {
        auto u = q[x].front();
        q[x].pop();
        u.step = s[x];
        qt.push(u);
    }
    bfs(x);
    return q[x].size();
    //队列中还有 说明还能继续扩展
}

int main()
{
    scanf("%d%d%d", &n, &m, &p);
    for(int i = 1; i <= p; i++)
        scanf("%d", &s[i]);
    for(int i = 1; i <= n; i++)
    {
        scanf("%s", t[i]+1);
        for(int j = 1; j <= m; j++)
            if(t[i][j] >= '1' && t[i][j] <= '9')
                a[i][j] = t[i][j] - '0';
    }

    for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
    {
        if(a[i][j] != 0 && a[i][j] != -1)
        q[a[i][j]].push(Node{i, j, s[a[i][j]]});
    }
    while(1)
    {
        bool flag = 0;
        for(int i = 1; i <= p; i++)
            flag |= solve(i);
        if(!flag) break;
    }

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            if(a[i][j] != -1 && a[i][j] != 0)
                ans[a[i][j]]++;
        }
    for(int i = 1; i <= p; i++)
        printf("%d ", ans[i]);
    return 0;
}

E. Helping Hiasat

  • 最大独立集板题,待补。

猜你喜欢

转载自www.cnblogs.com/zxytxdy/p/12208050.html