ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2018 ICPC 北京区域赛 I - Palindromes(规律+大数+模拟)

2021-01-13 19:29:04  阅读:369  来源: 互联网

标签:... Palindromes string temp 10 int ICPC 2018 size


传送门


题目大意

回文数字是指合法的字符串数字,然后是回文字符串。输出第 k ( k ≤ 1 0 100000 ) k(k \leq 10^{100000}) k(k≤10100000)个回文字符串。

解题思路

k k k这么大,显然是找规律的题目,那么不难发现回文数的个数应该按照位数来看,然后找到每个区间:

  • 位数为 1 1 1: [ 0 , 9 ] [0,9] [0,9]共 10 10 10个;包含的个数区间为 [ 1 , 10 ] [1,10] [1,10]
  • 位数为 2 2 2: [ 11 , 99 ] [11,99] [11,99]共 9 9 9个;包含的个数区间为 [ 11 , 19 ] [11,19] [11,19]
  • 位数为 3 3 3: [ 101 , 191 ] , [ 202 , [ 292 ] , . . . , [ 909 , 999 ] [101,191],[202,[292],...,[909,999] [101,191],[202,[292],...,[909,999]共 90 90 90个;包含的个数区间为 [ 20 , 109 ] [20,109] [20,109]
  • 位数为 4 4 4: [ 1001 , 1991 ] , [ 2002 , [ 2992 ] , . . . , [ 9009 , 9999 ] [1001,1991],[2002,[2992],...,[9009,9999] [1001,1991],[2002,[2992],...,[9009,9999]共 90 90 90个;包含的个数区间为 [ 110 , 199 ] [110,199] [110,199]
  • 位数为 5 5 5: [ 10001 , 19991 ] , [ 20002 , [ 29992 ] , . . . , [ 90009 , 99999 ] [10001,19991],[20002,[29992],...,[90009,99999] [10001,19991],[20002,[29992],...,[90009,99999]共 900 900 900个;包含的个数区间为 [ 200 , 1099 ] [200,1099] [200,1099]
  • 位数为 6 6 6: [ 100001 , 199991 ] , [ 200002 , [ 299992 ] , . . . , [ 900009 , 999999 ] [100001,199991],[200002,[299992],...,[900009,999999] [100001,199991],[200002,[299992],...,[900009,999999]共 900 900 900个;包含的个数区间为 [ 1100 , 1999 ] [1100,1999] [1100,1999]

对于一个超大的给定的 k k k,我们需要首先确定它在哪个区间内,这个我们可以预处理每个区间的左端点(有规律的),然后分奇偶找每种区间的规律,对于第 i i i个长度为 x x x的区间, k − L i ∈ [ 0 , x − 1 ] k-L_i \in [0,x-1] k−Li​∈[0,x−1],然后我们找规律发现:

  • 若 i i i为奇数,那么将上面作差的结果对齐为 ⌊ d e l t a 2 ⌋ + 1 \lfloor \frac{delta}{2}\rfloor + 1 ⌊2delta​⌋+1,然后从左到右除第一位的每一位都是长度为 i i i位的答案从左到右的每一位,这里先不考虑回文的对称(第一位需要加上1)
  • 若 i i i为偶数,那么将上面作差的结果对齐为 ⌊ d e l t a 2 ⌋ \lfloor \frac{delta}{2}\rfloor ⌊2delta​⌋,然后从左到右除第一位的每一位都是长度为 i i i位的答案从左到右的每一位,这里先不考虑回文的对称(第一位需要加上1)

对于第一步如何找到对应的左端点,我一开始写预处理,然后 M L E MLE MLE了,然后每次 O ( n ) O(n) O(n)去找,结果
T L E TLE TLE了,然后仔细观察,只需要看 k k k的位数会落在哪些区间——对于给定位数的数只可能在三个区间内,且是有规律的,那么我们每次都处理出这三个左端点看在哪个左端点的区间内即可。

#include <bits/stdc++.h>

using namespace std;
#define ENDL "\n"
const int maxn = 1e5 + 10;

string sub(string a, string b, int len) {  //大数减法
    int len1 = a.size(), len2 = b.size();
    string c = "";
    int cnt = len1 - len2;
    while (cnt--) c += '0';
    c += b;
    for (int i = len1 - 1; i >= 0; i--) {
        if (a[i] >= c[i]) {
            a[i] = (a[i] - '0') - (c[i] - '0') + '0';
        } else {
            int j = i - 1;
            while (j > 0 && a[j] == '0') j--;
            a[j] = (a[j] - '0') - 1 + '0', j++;
            while (j <= i) a[j] = (a[j] - '0') + 10 + '0', j++;
            a[i] = (a[i] - '0') - (c[i] - '0') + '0';
        }
    }
    string ans = "";
    int x = len1 - len;
    // cout << len << " " << x << endl;
    for (int i = x; i < len1; i++) ans += a[i];
    return ans;
}

inline int cmp(const string &s1, const string &s2) {
    if (s1.size() > s2.size()) return 1;
    if (s1.size() < s2.size()) return -1;
    for (int i = 0; i < s1.size(); i++) {
        if (s1[i] > s2[i])
            return 1;
        else if (s1[i] < s2[i])
            return -1;
    }
    return 0;
}

int pos;  //最后答案的长度
string L[5];

string Find(string s) {
    int len = s.size();
    L[1] = L[2] = L[3] = L[4] = "";
    L[1] += '2';
    for (int i = 1; i <= len - 2; i++) L[1] += '0';
    L[2] += "11";
    for (int i = 1; i <= len - 2; i++) L[2] += '0';
    L[3] += '2';
    for (int i = 1; i <= len - 1; i++) L[3] += '0';
    L[4] += "11";
    for (int i = 1; i <= len - 1; i++) L[4] += '0';
    for (int i = 1; i <= 3; i++) {
        if (cmp(s, L[i]) >= 0 && cmp(s, L[i + 1]) < 0) {
            pos = len * 2 - 4 + i;
            return L[i];
        }
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t;
    string k;
    cin >> t;
    while (t--) {
        cin >> k;
        if (k.size() == 1) {
            cout << (char)(k[0] - 1) << ENDL;
            continue;
        }
        if (k == "10") {
            cout << "9" << ENDL;
            continue;
        }
        if (cmp(k, "11") >= 0 && cmp(k, "19") <= 0) {
            k[0] = k[1];
            cout << k << ENDL;
            continue;
        }
        string L = Find(k), res, temp = "", ans = "";
        //cout << L << " " << pos << endl;
        if (pos & 1) {
            res = sub(k, L, pos / 2 + 1);
            // cout << res << endl;
            temp += (res[0] - '0') + 1 + '0';
            for (int i = 1; i < res.size(); i++) {
                temp += res[i];
            }
            ans = temp;
            for (int i = temp.size() - 2; i >= 0; i--) ans += temp[i];
        } else {
            res = sub(k, L, pos / 2);
            // cout << res << endl;
            temp += (res[0] - '0') + 1 + '0';
            for (int i = 1; i < res.size(); i++) {
                temp += res[i];
            }
            ans = temp;
            for (int i = temp.size() - 1; i >= 0; i--) ans += temp[i];
        }
        cout << ans << ENDL;
    }
    return 0;
}

标签:...,Palindromes,string,temp,10,int,ICPC,2018,size
来源: https://blog.csdn.net/qq_44691917/article/details/112580491

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有