A. Peaceful Rooks

目录

1.Problem

2.Input

3.Output

4.Examples

4.1input

4.2output

5.Code

6.Conclusion


1.Problem

You are given a n×nn×n chessboard. Rows and columns of the board are numbered from 11 to nn. Cell (x,y)(x,y) lies on the intersection of column number xx and row number yy.

Rook is a chess piece, that can in one turn move any number of cells vertically or horizontally. There are mm rooks (m<nm<n) placed on the chessboard in such a way that no pair of rooks attack each other. I.e. there are no pair of rooks that share a row or a column.

In one turn you can move one of the rooks any number of cells vertically or horizontally. Additionally, it shouldn't be attacked by any other rook after movement. What is the minimum number of moves required to place all the rooks on the main diagonal?

The main diagonal of the chessboard is all the cells (i,i)(i,i), where 1≤i≤n1≤i≤n.

2.Input

The first line contains the number of test cases tt (1≤t≤1031≤t≤103). Description of the tt test cases follows.

The first line of each test case contains two integers nn and mm — size of the chessboard and the number of rooks (2≤n≤1052≤n≤105, 1≤m<n1≤m<n). Each of the next mm lines contains two integers xixi and yiyi — positions of rooks, ii-th rook is placed in the cell (xi,yi)(xi,yi) (1≤xi,yi≤n1≤xi,yi≤n). It's guaranteed that no two rooks attack each other in the initial placement.

The sum of nn over all test cases does not exceed 105105.

3.Output

For each of tt test cases print a single integer — the minimum number of moves required to place all the rooks on the main diagonal.

It can be proved that this is always possible.

4.Examples

4.1input

4
3 1
2 3
3 2
2 1
1 2
5 3
2 3
3 1
1 2
5 4
4 5
5 1
2 2
3 3

4.2output

1
3
4
2

5.Code

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

template <typename T> bool chkmax(T &x, T y) { return x < y ? x = y, true : false; }
template <typename T> bool chkmin(T &x, T y) { return x > y ? x = y, true : false; }

int readint() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

const int MAXN = 100005;

int n, x, y;
char s[MAXN];
int cnt0[MAXN], cnt1[MAXN], cntq[MAXN];
ll pre0[MAXN], pre1[MAXN], suf0[MAXN], suf1[MAXN];

int main() {
    scanf("%s", s + 1);
    n = strlen(s + 1);
    x = readint();
    y = readint();

    int n0 = count(s + 1, s + n + 1, '0');
    int n1 = count(s + 1, s + n + 1, '1');
    ll ans = 0;

    for (int i = 1; i <= n; i++) {
        cnt0[i] = cnt0[i - 1] + (s[i] == '0');
        cnt1[i] = cnt1[i - 1] + (s[i] == '1');
        cntq[i] = cntq[i - 1] + (s[i] == '?');

        if (s[i] == '0') ans += 1LL * y * cnt1[i];
        else if (s[i] == '1') ans += 1LL * x * cnt0[i];
        else {
            pre0[i] = 1LL * y * cnt1[i] + 1LL * x * (n1 - cnt1[i]);
            pre1[i] = 1LL * x * cnt0[i] + 1LL * y * (n0 - cnt0[i]);
            suf0[i] = 1LL * y * cnt1[i] + 1LL * x * (n1 - cnt1[i]);
            suf1[i] = 1LL * x * cnt0[i] + 1LL * y * (n0 - cnt0[i]);
        }
    }

    for (int i = 1; i <= n; i++) pre0[i] += pre0[i - 1], pre1[i] += pre1[i - 1];
    for (int i = n; i >= 1; i--) suf0[i] += suf0[i + 1], suf1[i] += suf1[i + 1];

    ll now = LLONG_MAX;

    for (int i = 0; i <= n; i++) {
        chkmin(now, pre0[i] + suf1[i + 1] + 1LL * x * cntq[i] * (cntq[n] - cntq[i]));
        chkmin(now, pre1[i] + suf0[i + 1] + 1LL * y * cntq[i] * (cntq[n] - cntq[i]));
    }

    printf("%lld\n", ans + now);
    return 0;
}

6.Conclusion

这段代码实现了一个处理字符串的程序。具体来说,程序的作用如下:

1.通过读入一个字符串 s,以及两个整数 x 和 y,其中 x 和 y 是替换字符 '0' 和 '1' 的代价。
2.统计字符串中 '0' 和 '1' 的个数分别为 n0 和 n1。
3.通过遍历字符串,计算在每个位置上替换 '0' 和 '1' 所需要的代价,并存储在相应的数组中(如 pre0、pre1、suf0、suf1)。
4.利用前缀和数组,计算在每个位置上替换 '?' 所需要的代价,并在过程中更新最小代价 now。
5.最终输出替换所有字符的最小代价。

总体来说,这段代码的目标是找到一种替换字符的方案,使得替换后的字符串的总代价最小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向阳而生__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值