Codeforces Round #506 (Div. 3)

Posted kisekipurin2019

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #506 (Div. 3)相关的知识,希望对你有一定的参考价值。

题目链接:https://codeforces.com/contest/1029

A - Many Equal Substrings

题意:给一个长度为 (n(1leq nleq50)) 的字符串 (t) ,和一个正整数 (k(1leq kleq50)) ,要求构造一个最短的字符串 (s) ,使得 (t)(s) 中恰好出现 (k) 次。

题解:看起来就像KMP算法,来个 (O(n^3)) 的做法就可以了,枚举重叠部分的两个开始位置,然后判断是否重叠,用此找出最长的重叠位置。但是直接复制一个前缀函数来用最简单。

在模板中提供的前缀函数是要求从0开始的,而 (pi(n)) 即为整个字符串除去字符串本身的首尾重叠的最长长度。

注意留够空间。

int pi[3005];
void GetPrefixFunction(char *s, int sl) {
    pi[0] = 0, pi[1] = 0;
    for(int i = 1, k = 0; i < sl; ++i) {
        while(k && s[i] != s[k])
            k = pi[k];
        pi[i + 1] = (s[i] == s[k]) ? ++k : 0;
    }
}

char s[3005];

void test_case() {
    int n, k;
    scanf("%d%d%s", &n, &k, s);
    GetPrefixFunction(s, n);
    int p = pi[n];
    int top = n;
    --k;
    while(k--) {
        for(int i = 0; i < n - p; ++i) {
            s[top] = s[top - (n - p)];
            ++top;
        }
    }
    s[top] = '';
    puts(s);
}

B - Creating the Contest

题意:给一个长度为 (n(1leq n leq 2cdot 10^5)) 的严格单调递增的数列,要求从中选出若干个数,使得除了最大的那个数外,每个数都存在一个比它大且不超过它的两倍的数。

题解:很显然最容易满足“比某个数大且不超过它的两倍”的是它的下一个数,意思是一旦断掉就要重新开始咯。

int a[200005];

void test_case() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    int ans = 1, cur = 1;
    for(int i = 2; i <= n; ++i) {
        if(a[i] > a[i - 1] * 2)
            cur = 1;
        else {
            ++cur;
            ans = max(ans, cur);
        }
    }
    printf("%d
", ans);
}

C - Maximal Intersection

题意:给 (n(2leq n leq 3cdot 10^5)) 条线段,移除恰好一条线段使得剩下的 (n-1) 条线段的交尽可能长。

题解:上次不是做过一个矩形版的吗?我还是用扫描线做的。这个直接维护线段的前缀交和后缀交就可以了。

int l[300005], r[300005];
int pl[300005], pr[300005];
int sl[300005], sr[300005];

void test_case() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d%d", &l[i], &r[i]);
    pl[0] = -INF, pr[0] = INF;
    for(int i = 1; i <= n; ++i) {
        pl[i] = max(pl[i - 1], l[i]);
        pr[i] = min(pr[i - 1], r[i]);
    }
    sl[n + 1] = -INF, sr[n + 1] = INF;
    for(int i = n; i >= 1; --i) {
        sl[i] = max(sl[i + 1], l[i]);
        sr[i] = min(sr[i + 1], r[i]);
    }
    int ans = 0;
    for(int i = 1; i <= n; ++i) {
        int L = max(pl[i - 1], sl[i + 1]);
        int R = min(pr[i - 1], sr[i + 1]);
        //printf("L=%d R=%d
", L, R);
        ans = max(ans, R - L);
    }
    printf("%d
", ans);
}

D - Concatenated Multiples

题意:给 (n(2leq n leq 2cdot 10^5)) 个正整数和一个正整数 (k) ,求有多少个有序数对 ((i,j) (i eq j)) 使得第 (i) 个数后面接上第 (j) 个数之后被 (k) 整除。

题解:处理出每个数模 (k) 的余数,分长度存储在map里面。然后枚举第一个数和第二个数的长度(第一个数左移的量),就可以在对应的map里面查到有多少个数满足题意了。最后把 ((i,i)) 的情况去掉。

注意:1e9接在1e9后面是大概1e19,会溢出。要考虑模运算对四则运算的等价变换。

int a[200005];
map<int, int> m[11];

int GetLen(int x) {
    int len = 1;
    while(x >= 10) {
        x /= 10;
        ++len;
    }
    return len;
}

ll GetXX(int x, int len, int k) {
    ll cur = 1;
    while(len--)
        cur *= 10;
    cur += 1;
    cur %= k;
    cur *= x;
    cur %= k;
    return cur;
}

void test_case() {
    int n, k;
    scanf("%d%d", &n, &k);
    ll ans = 0;
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        int len = GetLen(a[i]);
        m[len][a[i] % k]++;
        if(GetXX(a[i], len, k) == 0)
            --ans;
    }
    for(int i = 1; i <= n; ++i) {
        ll cur = a[i];
        for(int j = 1; j <= 10; ++j) {
            cur *= 10;
            cur %= k;
            int t = (k - cur) % k;
            auto it = m[j].find(t);
            if(it != m[j].end())
                ans += (*it).second;
        }
    }
    printf("%lld
", ans);
}

以上是关于Codeforces Round #506 (Div. 3)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #506 (Div. 3)

Codeforces Round #506 (Div. 3) C. Maximal Intersection

Codeforces Round #506 (Div. 3) C. Maximal Intersection (枚举)

Codeforces Round #506 (Div. 3) D. Concatenated Multiples

Codeforces Round #506 (Div. 3) D-F

Codeforces Round #506 D. Concatenated Multiples题解