【解题报告】Codeforces Round #344 (Div. 2)

题目链接

A.Interview(Codeforces 631A)

分析

显然,根据兼或和的性质,当 l r 分别为 1 n 时最后的结果最大。

代码

#include <bits/stdc++.h>
using namespace std;

long long  n, a, b, sa, sb;

int main() {
    scanf("%d", &n);
    sa = sb = 0;
    for(int i = 0; i < n; i++) {
        scanf("%I64dd", &a);
        sa |= a;
    }
    for(int i = 0; i < n; i++) {
        scanf("%I64d", &b);
        sb |= b;
    }
    printf("%I64d\n", sa + sb);
    return 0;
}

B.Print Check(Codeforces 631B)

分析

显然,这题直接暴力是不行的。在不算主算法的情况下,输入的复杂度是 O(k) ,输出的复杂度是 O(nm) 。这就表示本题仅允许我们在输入的同时维护一些量,然后在输出的时候,对矩阵的每一个元素,根据这些量来决定元素的值。对于一个元素 (i,j) 而言,若要知道它最终的值是多少,仅需知道它最终被刷上什么颜色,也就是说,仅需知道它所在的行的最终颜色,它所在的列的最终颜色,以及这两个颜色出现的先后顺序。总而言之,我们需要对每一行,每一列维护最后被涂上的颜色和被涂上的时间。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5e3 + 5;int n, m, k, a, b, c;
int cr[maxn], cc[maxn], pr[maxn], pc[maxn];
int G[maxn][maxn];

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= k; i++) {
        scanf("%d%d%d", &a, &b, &c);
        if(a == 1) {
            cr[b] = c;
            pr[b] = i;
        }
        else {
            cc[b] = c;
            pc[b] = i;
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            G[i][j] = pr[i] > pc[j] ? cr[i] : cc[j];
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            printf("%d ", G[i][j]);
        }
        puts("");
    }
    return 0;
}

C.Report(Codeforces 631C)

分析

本题用暴力的方法肯定也是不行的了。既然题目给的每次排序的区间是前缀,那么就应该充分利用前缀的性质。不难发现,对 [0,r] 这个前缀排序以后,在这个排序之前的对长度小于r的前缀的排序都无效了。所以有效的前缀的长度应该是递减的。那么我们可以用数组模拟的单调队列来存储这些递减的前缀。然后对这些前缀依次排序就可以常数地优化时间。不过可惜的是,这样的优化仍然不够。现假设已经对长度为 ri 的前缀排序完毕。在对长度为 ri+1 的前缀排序前,我们首先可以将 [ri+1+1,ri] 的排序结果的出来,因为以后的排序不会再影响这个区间内的元素的顺序。于是对 i 循环即可得到全部结果。注意,每次排序不能真的去排序,我们应该用 bl,br 两个指针来维护剩余的区间,然后根据 ti 来决定取数是从区间的哪头开始。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;
int n, m, cnt, bl, br, a[maxn], b[maxn], t[maxn], r[maxn];

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    cnt = 0;
    for(int ti, ri; m--;) {
        scanf("%d%d", &ti, &ri);
        while(cnt && ri > r[cnt-1]) {
            cnt--;
        }
        t[cnt] = ti;
        r[cnt++] = ri;
    }
    for(int i = 1; i <= r[0]; i++) {
        b[i] = a[i];
    }
    sort(b + (bl = 1), b + (br = r[0]) + 1);
    r[cnt++] = 0;
    for(int i = 0; i < cnt; i++) {
        for(int j = r[i-1]; j > r[i]; j--) {
            a[j] = t[i-1] == 1 ? b[br--] : b[bl++] ;
        }
    }
    for(int i = 1; i <= n; i++) {
        printf("%d ", a[i]);
    }
    return 0;
}

D.Messenger(Codeforces 631D)

分析

将字符串“解压”后KMP匹配显然是会超时的。于是考虑能否直接用压缩后的信息来匹配。于是可以将压缩后的串当成“字符串”,对于在模式“字符串”两头的“字符” cl ,只要在文本串中存在 c0l0 ,满足 c0=c l0l 就表示模式串和文本串中的这两个“字符”相等。对于在模式串中间(不在两端)的“字符” cl ,在文本串中存在 c0l0 ,必须满足 c=c0 l=l0 才能表示“字符”相等。如此,将结构体 (c,l) 当成字符,进行KMP匹配,统计匹配数量就能得到答案。注意要将输入中相同的“字符”合并,并且要特判只有一个“字符”的情况。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair <ll, char> p;
const int maxn = 2e5 + 5;
int n, m, next[maxn];
ll ans;
vector <p> v[2];

void input(int n, int d) {
    char ch;
    int num;
    for(int i = 0; i < n; i++) {
        scanf("%d-%c", &num, &ch);
        if(v[d].size() && v[d].back().second == ch) {
            v[d].back().first += num;
        }
        else v[d].push_back(p(num, ch));
    }
}

void getNext() {
    int j, k;
    next[j=0] = k = -1;
    while(j < v[1].size()) {
        if(k == -1 || v[1][k] == v[1][j]) {
            next[++j] = ++k;
        }
        else k = next[k];
    }
}

bool judge(p x, p y) {
    return x.first >= y.first && x.second == y.second;
}

void kmpCount() {
    int j = 0;
    for(int i = 0; i < v[0].size(); i++) {
        if(j == v[1].size() - 1 && judge(v[0][i], v[1][j])) {
            j++;
        }
        else {
            while(j && v[0][i] != v[1][j]) {
                j = next[j];
            }
            if(v[0][i] == v[1][j] || !j && judge(v[0][i], v[1][j])) {
                j++;
            }
        }
        if(j == v[1].size()) {
            j = next[j];
            ans++;
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    input(n, 0);
    input(m, 1);
    if(v[1].size() > 1) {
        getNext();
        kmpCount();
    }
    else for(int i = 0; i < v[0].size(); i++) {
        if(!judge(v[0][i], v[1][0])) continue;
        ans += (v[0][i].first - v[1][0].first + 1);
    }
    printf("%I64d\n", ans);
    return 0;
}

你可能感兴趣的:(codeforces,344,631)