AtCoder Regular Contest 153

A - AABCDDEFE (arc153 a)

题目大意

给定一个仅包含数字的字符串,称它为好的,当且仅当其包含\(9\)个数字,且

  • \(s_1 \neq 0\)
  • \(s_1 = s_2\)
  • \(s_5 = s_6\)
  • \(s_7 = s_9\)

给定\(N\),问字符串第 \(N\)小的好串。

解题思路

自由位置其实只有\(s_1,s_3,s_4,s_5,s_7,s_8\)六个,因此可以预处理这\(10^6\)个,或者将\(N\)每位拆解赋值到对应位置即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    LL n;
    cin >> n;
    -- n;
    vector<int> qwq;
    while(n){
        qwq.push_back(n % 10);
        n /= 10;
    }
    string s(9, '0');
    s[0] = '1';
    s[1] = '1';
    if (qwq.size() > 0)
        s[7] += qwq[0];
    if (qwq.size() > 1){
        s[6] += qwq[1];
        s[8] += qwq[1];
    }
    if (qwq.size() > 2){
        s[4] += qwq[2];
        s[5] += qwq[2];
    }
    if (qwq.size() > 3){
        s[3] += qwq[3];
    }
    if (qwq.size() > 4){
        s[2] += qwq[4];
    }
    if (qwq.size() > 5){
        s[1] += qwq[5];
        s[0] += qwq[5];
    }
    cout << s << '\n';

    return 0;
}



B - Grid Rotations (arc153 b)

题目大意

给定一个\(h\times w\)的网格,进行 \(q\)次操作,每次操作包含两个数\(x,y\),将网格分成四部分,其中左上部分的右下角为 \(x,y\),然后对四个部分分别旋转180度。

\(q\)次操作的网格图样子。

解题思路

考虑一维的情况,比如 1 2 3 4 5 6,我们将头尾视为相连,即\(1\)的左边是 \(6\)。假定选择一个位置进行翻转,比如选择 4,就变成4 3 2 1 6 5,观察1左右两边的数,始终都是 2,6,只是左右方向变了,其他数亦是如此。

因此将头尾连成一个环形关系,每次操作都不会改变该环形关系,只是左右对调了。

拓展到二维的话,就是将上下相连,左右相连,形成一个球形关系,每次操作同样不会改变这个球形关系,只是上下交换,左右交换了。

因此我们只要处理出一个位置经过\(q\)次操作后的位置,然后再根据原来的球形关系还原出答案即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int h, w;
    cin >> h >> w;
    vector<string> s(h);
    for(auto &i : s){
        cin >> i;
    }
    int sx = 0, sy = 0;
    auto change = [&](int x, int y){
        if (sx <= x){
            int rh = x + 1;
            sx = rh - sx - 1;
        }else {
            int rh = h - x - 1;
            sx -= x + 1;
            sx = rh - sx - 1;
            sx += x + 1;
        }
        if (sy <= y){
            int rw = y + 1;
            sy = rw - sy - 1;
        }else {
            int rw = w - y - 1;
            sy -= y + 1;
            sy = rw - sy - 1;
            sy += y + 1;
        }
    };
    int q;
    cin >> q;
    int dir = -2 * (q & 1) + 1;
    while(q--){
        int x, y;
        cin >> x >> y;
        -- x, --y;
        change(x, y);
    }
    vector<vector<char>> ans(h, vector<char>(w));
    for(int i = 0; i < h; ++ i){
        for(int j = 0; j < w; ++ j){
            ans[sx][sy] = s[i][j];
            sy = (sy + w + dir) % w;
        }
        sx = (sx + h + dir) % h;
    }
    for(auto &i : ans){
        for(auto &j : i)
            cout << j;
        cout << '\n';
    }

    return 0;
}



C - ± Increasing Sequence (arc153 c)

题目大意

给定一个长度为\(n\),仅包含\(-1,1\)的数组 \(a\)。要求构造一个长度一样为\(n\)的数组\(x\),满足

  • \(|x_i| \leq 10^{12}\)
  • 数组\(x\)严格递增
  • \(\sum_{i=1}^{n} a_i x_i = 0\)

不存在则告知该事实。

解题思路

想的很朴素,就是先填充\(x\)\(1,2,3,...,n\)。然后计算下 \(sum = \sum a_i x_i\)的值。

  • 如果 \(sum = 0\)就皆大欢喜。
  • 如果 \(sum < 0\),就找一个数组\(a\)前缀和为\(-1\)的下标 \(pos\),则 \(x_i -= 1, i \in [1,pos]\)\(sum\)的值就会 \(+1\)。因此令 \(x_i -= (-sum), i \in [1, pos]\) ,这样\(sum\)就变成 \(0\)了,同时还保证了递增条件。因为\(|sum| \leq n^2 = 10^{10}\),因此\(x_i\)不会 超出范围。
  • 如果 \(sum > 0\),就找一个数组\(a\)前缀和为\(1\)的下标 \(pos\),则 \(x_i -= 1, i \in [1,pos]\)\(sum\)的值就会 \(-1\)。因此令 \(x_i -= (sum), i \in [1, pos]\) ,这样\(sum\)就变成 \(0\)了。同时还保证了递增条件。因为\(|sum| \leq n^2 = 10^{10}\),因此\(x_i\)不会 超出范围。

如果找不到对应的下标,就无解了(应该指这类初始情况的填法无解,因为初始严格递增的填法限制了改动范围只能是个前缀或后缀,但不清楚能否对应原问题的无解)(原本还想着倒着找个后缀和+1的,但过了)被评论区数据hack了,加上了这个判断。

因为\(a\)只有 \(1\)\(-1\),所以其前缀和相邻项最多相差 \(1\),第一个大于 \(0\)的必然是 \(1\),反之也是 \(-1\)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    cin >> n;
    vector<LL> a(n);
    vector<LL> sufa(n);
    vector<LL> prea(n);
    for(auto &i : a)
        cin >> i;
    vector<LL> ans(n);
    LL st = 1;
    iota(ans.begin(), ans.end(), st);
    LL sum = 0;
    for(int i = 0; i < n; ++ i)
        sum += ans[i] * a[i];
    partial_sum(a.begin(), a.end(), prea.begin());
    partial_sum(a.rbegin(), a.rend(), sufa.rbegin());
    auto solve = [&](){
        if (sum == 0)
            return true;
        if (sum < 0){
            for(auto &i : prea)
                i *= -1;
            for(auto &i : sufa)
                i *= -1;
            sum *= -1;
        }
        int pos = 0;
        for(; pos < n; ++ pos)
            if (prea[pos] > 0)
                break;
        if (pos == n){
            for(pos = n - 1; pos >= 0; -- pos)
                if (sufa[pos] < 0)
                    break;
            if (pos == -1)
                return false;
            for(int i = n - 1; i >= pos; -- i)
                ans[i] += sum;
            return true;
        }else{
            for(int i = 0; i <= pos; ++ i){
                ans[i] -= sum;
            }
            return true;
        }
    };
    if (solve()){
        cout << "Yes" << '\n';
        for(auto &i : ans)
            cout << i << ' ';
        cout << '\n';
    }else{
        cout << "No" << '\n';
    }

    return 0;
}



D - Sum of Sum of Digits (arc153 d)

题目大意

给定一个长度为\(n\)的数组\(a\),要求找到一个 \(x\),使得 \(\sum_{i=1}^{n}f(a_i + x)\)最小,其中 \(f(x)\)表示 \(x\)在十进制下各个数字的和,比如 \(f(1223) = 1 + 2 + 2 + 3 = 8\)

输出该最小值。

解题思路

<++>

神奇的代码



E - Deque Minimization (arc153 e)

题目大意

<++>

解题思路

<++>

神奇的代码



F - Tri-Colored Paths (arc153 f)

题目大意

<++>

解题思路

<++>

神奇的代码



posted @ 2023-01-15 16:46  ~Lanly~  阅读(191)  评论(2编辑  收藏  举报