AtCoder Beginner Contest 363

题目链接:AtCoder Beginner Contest 363

总结:前三题过于easy了,C的暴力写挂了一发。D差一点?,差一点总结;

A. Piling Up

fag:签到

B. Japanese Cursed Doll

fag: 签到

Solution:排序后求第\(p\)个数的值与\(t\)的差即可。

C. Japanese Cursed Doll

fag:模拟

Solution:暴力模拟即可

void solve(){
    cin >> n >> k;
    string s;
    cin >> s;

    int ans = 0;
    sort(s.begin(), s.end());
    do {
        bool fllag = true;
        for (int i = 0; i + k - 1 < n; i ++){
            bool flag = true;
            for (int tt = i, t = i + k - 1; tt <= t; tt ++ , t --){ // 判断每一个回文
                if (s[tt] != s[t]){  // 不是回文
                    flag = false;
                    break;
                }
            }
            if (flag){
                fllag = false;
                break;
            }

        }
        if (fllag)
            ans ++;

    }while (next_permutation(s.begin(), s.end()));
    
    cout << ans;
}

D.Palindromic Number

fag:思维?打表?

Description:求第\(n\)个回文数,不含前导零。\(1 <= n <= 1e18\)

Solution:考虑构造一个长度为\(n\)的回文数,显然对于偶数为只需要构造前一半就行,奇数位多了最中间的一位。

  • 显然我们不能直接求出第\(n\)个回文数,但是能够求出第\(n\)个回文数的长度,知道长度之后就能求这个长度对应的第几个回文数。
  • 打表或者模拟发现:奇数位的个数是上一位 * 10, 偶数位的个数等于上一位;如\(1111 => 11(0, 1, ...9)11\)中间可以填\(10\)个数,但是\(12321 => 123321\)只能将中间的数复制一下
1: 10
2: 9
3: 90
4: 90
5: 900
  • 然后我们一位一位找第\(n\)个回文数的长度,得到长度之后构造就行。

Competing:构造的时候细节出错了。

void solve(){
    int x;
    cin >> x;
    if (x <= 10){
        cout << x - 1 << endl;
        return;
    }

    /*
    枚举答案的位数:
    2: 9
    3: 90
    4: 90
    5: 900
    */

   int res = 9;
   LL ans = 10;  // 之前的和
   for (int i = 2; ; i ++){
        if (i & 1){  // 奇数乘10
            res = res * 10;
        }

        if (x - ans <= res){  // 避免ans + res 爆longlong
            x -= ans;  // 当前位数的第几个数
            if (i & 1){
                i /= 2;
                int t = (x + 9) / 10;  // 前缀是多少
                int tt = ((x - 1) % 10 + 10) % 10;  // 奇数位是几
                // debug(x, t, tt);
                t = qmi(10, i - 1) + t - 1;
                string s  = to_string(t);
                cout << s;
                cout << tt;
                reverse(s.begin(), s.end());
                cout << s;
                cout << endl;
                return;
            }
            else{  // 偶数从100 ~ 999
                i /= 2;
                int t = qmi(10, i - 1) + x - 1;
                string s  = to_string(t);
                cout << s;
                reverse(s.begin(), s.end());
                cout << s;
                cout << endl;
                return;
            }
        }
        
        ans += res;
   }
}

E. Sinking Land

fag:优先队列 + bfs

Description:有一个\(n * m\)的小岛,每个小岛的高度为\(a_{ij}\)。每天海水的高度\(+1\)(初始为\(0\)),当小岛的高度小于等于海水的高度时并且四个方向有相邻的海水时,小岛会被淹没变为海水,求每天未被淹没的海水。

Solution:显然我们是需要bfs的,然后我们使用优先队列存储。队头的元素小于海水高度时就直接出队。

Competing:写bfs出队时,猜设置访问状态st,应该先设置状态st,再入队,否则会有许多重复的点入队

void solve(){
    cin >> n >> m >> k;

    vector a(n + 5, vector<int>(m + 5));
    vector st(n + 5, vector<int>(m + 5));

    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            cin >> a[i][j];
    
    priority_queue<pair<int, pii>, vector<pair<int, pii>>, greater<pair<int, pii>>> qu;

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++){
            if (i == 1 || i == n || j == 1 || j == m)
            {
                qu.push({a[i][j], {i, j}});
                st[i][j] = true;
            }
        }
    
    int res = n * m;
    for (int i = 1; i <= k; i ++){
        while (qu.size() && qu.top().fi <= i){
            auto [t, tt] = qu.top();
            qu.pop();
            auto [x, y] = tt;
            res --;
            for (int j = 0; j < 4; j ++){
                int dx = x + dir[j][0], dy = y + dir[j][1];
                if (dx < 1 || dx > n || dy < 1 || dy > m || st[dx][dy])
                    continue;
                st[dx][dy] = true;
                qu.push({a[dx][dy], {dx, dy}});
            }
        }
        cout << res << endl;
    }
}

F. Palindromic Expression

fag:递归 +构造

Description:用\(1, 2, 3, 4, 5, 6 ,7, 8, 9, *\)构造一个回文串,满足以字母开头并且表达式的值为\(n\),求该回文串,不存在输入\(-1\)

\(1 <= n <= 1e12\)

Solution:先考虑给定的值就是一个回文串并且里面不含\(0\)那么直接输出。

  • 首先枚举\(n\)的因数,如果n mod x == 0并且\(x\)中不含\(0\)\(x\)是回文数;\(y\)\(x\)的回文数,且n / x mod y == 0,那么我们只需要考虑\(n / x / y\),如果构造就行。

  • 因此我们定义一个函数\(f\):如果\(x\)是回文串并且里面不含\(0\)那么直接返回。

  • 否则枚举它的因数,当因数\(x\)满足上面说所的条件,递归到\(f(n / x / y)\)

Competing:忘记考虑因数中也不能含\(0\)了。

int reverse(int x){  // 返回x的回文数
    string t = to_string(x);
    reverse(t.begin(), t.end());
    int y = stol(t);

    return y;
}

bool is_Hui(int x){ // 判断x是否是回文数
    string s = to_string(x);
    for (int i = 0, j = s.size() - 1; i <= j; i ++, j --){
        if (s[i] != s[j] || s[i] == '0')
            return false;
    }

    return true;
}

string f(int x){
    string s = to_string(x);
    if (is_Hui(x))  // 如果x是回文数,并且不含0之间返回
        return s;
    
    for (int i = sqrt(x) + 1; i >= 2; i --){  // 枚举x的质因数
        if (x % i == 0 && to_string(i).find('0') == -1){
            int y = reverse(i);  // i的回文数
            if ((x / i) % y == 0){
                string t = f(x / i / y);
                if (t != "0"){
                    return to_string(i) + "*" + t + "*" + to_string(y);
                }
            }
        }
    }

    return "0";
}

void solve(){
    int n;
    cin >> n;

    string ans = f(n);
    if (ans == "0" || ans.size() > 1000)
        cout << -1 << endl;
    else
        cout << ans << endl;
}
posted @ 2024-07-23 01:01  Sakura17  阅读(0)  评论(0编辑  收藏  举报