341

A - Print 341

给定一个正整数 N,打印一个由 N 个 0 和 N+1 个 1 组成的字符串,其中 01 交替出现。

void solve() {
    int n;cin >> n;
    string a = "";
    for (int i = 1;i <= n;i++) {
        a += "10";
    }
    a += "1";
    cout << a << '\n';
}

B - Foreign Exchange

N 个国家,编号为 1N。对于每个 i=1,2,,N,高桥有 Ai 个单位的 i 国货币。

高桥可以重复下面的操作任意多次,可能为零:

打印出高桥最终可能拥有的 N 国货币的最大单位数。

获得 Ti 个单位的 (i+1) 国货币 容易知道,肯定是一级一级向下传递的,所以直接贪心即可。

#define int long long
void solve() {
    int n;cin >> n;vector<int> a(n + 1);
    for (int i = 1;i <= n;i++) {
        cin >> a[i];
    }
    vector<pair<int, int>> s(n + 1);
    for (int i = 1;i <= n - 1;i++) {
        cin >> s[i].first >> s[i].second;
    }

    for (int i = 1;i <= n - 1;i++) {
        int bei = a[i] / s[i].first;
        a[i + 1] += bei * s[i].second;
    }
    cout << a[n] << '\n';
}

C - Takahashi Gets Lost

给定一个操作字符串和一个地图,若图上 . 按照操作字符串做完操作 位置全程在 . 上,则算是一个答案

char s[510][510];
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
void solve() {
    int h, w, n;cin >> h >> w >> n;
    string t;cin >> t;

    for (int i = 1;i <= h;i++) 
        for (int j = 1;j <= w;j++) 
            cin >> s[i][j];
    
    int ans = 0;
    for (int i = 2;i <= h - 1;i++) {
        for (int j = 2;j <= w - 1;j++) {
            bool ok = true;
            if (s[i][j] == '.') {
                int x = i, y = j;
                for (int k = 0;k < n;k++) {
                    int op = -1;
                    if (t[k] == 'U') {
                        op = 0;
                    } else if (t[k] == 'D') {
                        op = 1;
                    } else if (t[k] == 'L') {
                        op = 2;
                    } else if (t[k] == 'R') {
                        op = 3;
                    }
                    x += dx[op];
                    y += dy[op];
                    if (s[x][y] == '#') {
                        ok = false;break;
                    }
                }
                if (ok)ans++;
            }
        }
    }
    cout << ans << '\n';
}

D - Only one of two

给出 n,m,k(1nm108,1k1010),数组 an 的倍数和 m 的倍数且不包含 n×m 的倍数组成的序列求 a[k]

#define int long long
void solve() {
    int N, M, K;
    cin >> N >> M >> K;
    int low = 1, high = 1e18, ans = -1;

    while (low <= high) {
        int mid = (high + low) / 2;
        //lcm(a,b)=(a / __gcd(a, b)) * b
        int count = mid / N + mid / M - 2 * (mid / ((N / __gcd(N, M)) * M));
        if (count >= K) {
            ans = mid;
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    cout << ans << '\n';
}

Solution

二分

能被 NM 中的一者整除的数有 XN+XM2×XL 个。

官方题解:

NM 的最小公倍数记为 L
则在正整数 X 以下中,能被 NM 同时整除的数有 XL 个。因此,在 1X 之间,能被 NM 中的一者整除的数有 XN+XM2×XL 个。

此外,由于这个数目是关于 X 单调递增的,因此“答案要求在 X 以下”和“在 1X 之间,能被 NM 中的一者整除的数至少有 K 个”即 XN+XM2×XLK 是等价的。

因此,可以利用二分搜索来解决这个问题。在这个问题的限制下,答案一定不会超过 2×1018,因此可以将搜索范围设为 0 到 2×1018

答案小于等于 2×1018 的证明如下:不失一般性,设 N<M。设 NM 的最大公约数为 gN=ngM=mg1n<mnm 是整数)。则有

XN+XM2×XL>XN+XM2XL2=(m+n2)Xgnm2

X=2×1018 时,在问题的限制下有 m+n2n1Xgm2×1010,因此有

XN+XM2XL2=(m+n2)Xgnm22×10102

因此,在问题的限制下,在 X 以下一定至少有 2×10102 个符合条件的数,特别地也就至少有 K 个符合条件的数。实际上,对于当前限制,上限为 N=5×107M=108K=1010 时,答案为 10185×107

具体来说,可以首先设定 L=0,R=2×1018,然后只要 RL2,就重复以下步骤:

  1. X=L+R2
  2. 判断 XN+XM2×XLK,如果成立,则设 R=X,否则设 L=X

最终得到的 R 就是答案。

在固定 X 时,判断 XN+XM2×XLK 的复杂度为 O(1),而重复的次数最多也只有 60 次,因此非常高效。因此,这个问题可以用二分搜索很好地解决。

E - Alternating String

A string consisting of 0 and 1 is called a good string if two consecutive characters in the string are always different.

给你一个长度为 N 的 字符串 S ,由 01 组成。将给出 Q 个查询,必须按顺序处理。
查询有两种类型:

Solution

线段树

(待更 )