Codeforces Round 732 (Div

AquaMoon and Strange Sort

\(n\) 个人从左到右站成一排,从左数第 \(i\) 个人的衣服上印着 \(a_i\)。每个人的朝向可以是朝左、朝右。一开始所有人的方向都是朝右。

您可以对这些人做一些“操作”,每次操作允许您找两个相邻的人让他们交换顺序,但是在操作之后,两人都会掉头,也就是朝向都从朝右变成朝左或者相反。

现求是否存在一种操作方法使得操作完成后这 \(n\) 个人衣服上的数字 \(a_1, a_2, \ldots , a_n\) 从左往右读单调不减,并且最后所有人的方向都朝右。

题解:思维

  • 容易发现:如果一个人在交换顺序后方向始终向右的话,那么我们必须保证其交换次数为偶数

  • 同时题目限制我们只有相邻才能交换

  • 所以我们发现,如果存在一种合法的操作方法使得\(n\)个人的顺序单调递增,那么原本在偶数位置上的数字仍然会在偶数位置,原本在奇数位置上的数字仍然会在奇数位置

  • 所以我们不妨记录原本序列中偶数位置和奇数位置的状态,然后将该序列排序后,检查排序后偶数和奇数位置上的状态有没有变化即可

const int N = 2e5 + 10, M = 4e5 + 10;

int n;
int a[N], b[N];
int mp[N][2];

void solve()
{
    cin >> n;
    for (int i = 1; i <= 1e5; ++i)
        mp[i][0] = mp[i][1] = 0;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        b[i] = a[i];
        mp[a[i]][i % 2]++;
    }
    sort(b + 1, b + n + 1);
    for (int i = 1; i <= n; ++i)
        mp[b[i]][i % 2]--;
    for (int i = 1; i <= n; ++i)
    {
        if (mp[a[i]][i % 2])
        {
            cout << "NO" << endl;
            return;
        }
    }
    cout << "YES" << endl;
}

AquaMoon and Chess

你有一个长为 \(n\) 的棋盘,这个棋盘上有一些棋子,你可以进行如下操作:

如果第 \(i + 2\) 个位置是空的,且第 \(i + 1\) 个位置非空,则可以将第 \(i\) 个位置的棋子挪到第 \(i + 2\) 个位置 (\(i + 2 \leq n\)).

如果第 \(i - 2\) 个位置是空的,且第 \(i - 1\) 个位置非空,则可以将第 \(i\) 个位置的棋子挪到第 \(i - 2\) 个位置 (\(i - 2 \geq 1\)).

现在将给出一个棋盘的初始状态,求可以通过上述操作可以到达的状态数,你可以进行任意次操作,答案对 \(998244353\) 取模.

题解:思维 + 组合计数

  • 容易发现:如果现在棋盘为0110,那么最后能够到达的所有状态为0110,11000011,我们发现如果我们把11捆绑看成一个整体后,那么我们观察发现所有可以到达的状态就是110随意组合排序

  • 那么如果现在棋盘为01110,那么最后能够到达的所有状态为011101101000111 ,那么我们也可以发现,如果现在存在相邻的奇数个1的情况,但是我们发现,如果我们将11看成整体的话,实际上另一个1 位置是随着110位置的变化而被动移动的

  • 所以影响这个棋盘状态变化的是110之间的组合顺序,我们可以忽略单个1对整体状态的影响

  • 假设11的个数为cnt20的个数为cnt0,那么答案为

\[C_{cnt0+cnt2}^{cnt2} \]

const int N = 2e5 + 10, M = 4e5 + 10;

int n;

int qpow(int a, int b, int p)
{
    int res = 1;
    while (b)
    {
        if (b & 1)
            res = res * a % p;
        b >>= 1;
        a = a * a % p;
    }
    return res % p;
}

int C(int a, int b, int p)
{
    int res = 1;
    for (int i = 1, j = a; i <= b; ++i, --j)
    {
        res = res * j % p;
        res = res * qpow(i, p - 2, p) % p;
    }
    return res % p;
}

void solve()
{
    cin >> n;
    string s;
    cin >> s;
    int cnt0 = 0, cnt2 = 0;
    for (int i = 0; i < n; ++i)
    {
        if (s[i] == '0')
            cnt0++;
        else if (s[i] == '1')
        {
            if (s[i + 1] == '1')
            {
                cnt2++;
                i++;
            }
        }
    }
    cout << C(cnt0 + cnt2, cnt0, mod) << endl;
}
posted @ 2023-05-23 21:05  Zeoy_kkk  阅读(8)  评论(0编辑  收藏  举报