Codeforces Edu Round 65 A-E

A. Telephone Number

跟之前有一道必胜策略是一样的,\(n - 10\)位之前的数存在\(8\)即可。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 110;
int n;
char s[N];
int main(){
    int T; scanf("%d", &T);
    while(T--){
        scanf("%d%s", &n, s + 1);
        bool flag = false;
        for(int i = 1; i <= n - 10; i++)
            if(s[i] == '8') flag = true;
        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}

B. Lost Numbers

暴力枚举答案即可。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int a[6] = {4, 8, 15, 16, 23, 42};
int b[4];
bool inline judge(){
    for(int i = 0; i < 4; i++)
        if(a[i] * a[i + 1] != b[i]) return false;
    return true;
}
int main(){
    for(int i = 1; i <= 4; i++){
        printf("? %d %d\n", i, i + 1);
        fflush(stdout);
        scanf("%d", b + i - 1);
    }
    do{
        if(judge()){
            printf("! ");
            for(int i = 0; i < 6; i++)
                printf("%d ", a[i]);
            puts("");
            fflush(stdout);
            break;
        }
    }while(next_permutation(a, a + 6));
    return 0;
}

C. News Distribution

这...不是并查集裸题吗?

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 500010;
int n, m, f[N], size[N];
int inline find(int x){
    return f[x] == x ? x : f[x] = find(f[x]);
}
void inline merge(int x, int y){
    x = find(x), y = find(y);
    if(x == y) return ;
    if(size[x] > size[y]) swap(x, y);
    f[x] = y; size[y] += size[x];
}
int main(){
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        f[i] = i, size[i] = 1;
    }
    for(int i = 1; i <= m; i++){
        int k, x; scanf("%d", &k);
        if(!k) continue;
        scanf("%d", &x); 
        for(int j = 1, y; j < k; j++){
            scanf("%d", &y);
            merge(x, y);    
        }
    }
    for(int i = 1; i <= n; i++)
        printf("%d ", size[find(i)]);
    return 0;
}

D. Bicolored RBS

维护一个变量\(dep\),表示目前在第一层,只要奇偶异置,则符合要求,最大层数为\(\lceil maxDep / 2\rceil\)

#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
const int N = 200010;
char str[N];
int n, ans[N], dep = 0;
int main(){
    scanf("%d%s", &n, str + 1);
    for(int i = 1; i <= n; i++){
        if(str[i] == '('){
            ans[i] = (++dep) & 1;
        }else if(str[i] == ')'){
            ans[i] = (dep--) & 1;
        }
    }
    for(int i = 1 ;i <= n; i++) 
        printf("%d", ans[i]);
    return 0;
}

E. Range Deleting

\(Two - Pointer\)算法。我们发现两个性质:

  1. \((l, r)\)可行,那么\((l, r + 1) , (l, r + 2)...(l, x)\)都是可行的。因为在升序序列删东西还是升序的。

  2. \((l, r)\)不可行,那么\((l, r - 1) , (l, r - 2)...(l, l)\)都是不可行的。因为在已经不可行的序列加东西显然不想。

那么,对于每一个\(l (1 <= l <= x)\),我们找出一个最小的\(r\)使其满足条件,左端点为\(l\)对答案的贡献就是\(n - r + 1\)。我们称这个最小的\(r\)\(r_{min_l}\)

还有另外一个性质,在\(l\)增加之后,\(r_{min_l}\)只可能增加或不变,不可能减少。因为多露出数,要么符合条件,要么还需要减掉一些数。

想到这里,我们就可以用双指针算法了。我们还需要用\(O(1)\)的时间判断加入一个数是否可行。

我们可以用\(O(n)\)的时间预处理四个数组:

  1. \(S_i\) 代表数字\(i\)在数组中出现最早的位置
  2. \(T_i\) 代表数字\(i\)在数组中出现最晚的位置
  3. \(Sx_i\) 代表数字\(i\)\(x\)在数组中出现最早的位置
  4. \(Tx_i\) 代表数字\(1\)\(i\)在数组中出现最晚的位置
  • 对于左端\(l\)的处理,若我们想知道让\(l - 1\)移动到\(l\)是否可行:

\(Tx[l - 2] < S[l - 1]\),则小于\(l - 1\)的一切数位置都在第一个\(l - 1\)左边,就可以移动。

  • 对于右端点的处理,已确定\([1, l - 1]\)\([r + 1, x]\)范围内的数均满足条件,判断\((l, r)\),是否满足条件:

\(Tx_{l - 1} < Sx_{r + 1}\)表示所有小于等于\(l - 1\)的数都在大于\(r + 1\)的数的左边则满足条件,否则我们需要让\(r\)增加。

注意,在处理当中我们先找到一个最小的\(r\)使得\((1, r)\)满足条件,然后在扩大\(l\)的1过程当中,被迫增加\(r\),如性质\(2\)

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 1000010, INF = 0x3f3f3f3f;
typedef long long LL;
int n, x, S[N], T[N], Sx[N], Tx[N];
int a[N];
LL ans = 0;
int main(){
    memset(S, 0x3f, sizeof S);
    scanf("%d%d", &n, &x);
    for(int i = 1; i <= n; i++){
        scanf("%d", a + i);
        if(S[a[i]] == INF) S[a[i]] = i;
        T[a[i]] = i;
    }
    for(int i = 1; i <= x; i++)
        Tx[i] = max(Tx[i - 1], T[i]);
    
    Sx[x + 1] = INF;
    for(int i = x; i; i--)
        Sx[i] = min(Sx[i + 1], S[i]);
    
    int r = x - 1;
    while(r && T[r] < Sx[r + 1]) r--;
    for(int l = 1; l <= x; l++){
        if(l > 2 && S[l - 1] < Tx[l - 2]) break;
        while(r <= x && (r < l || Tx[l - 1] > Sx[r + 1])) 
            r++;
        ans += x - r + 1;
    }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/dmoransky/p/11311781.html
今日推荐