Codeforces Round #736 (Div. 2)

Codeforces Round #736 (Div. 2)

A. Gregor and Cryptography

  • 题意

给出一个p, 让你找到x,y令 \(x%p = y%p\)

  • 思路

签到思维,想一下mod p = 1的情况就行

code :

void solve(){
    int n;
    cin >> n;
    if(n == 5) {
        cout << "2 4" << endl;
        return;
    }
    cout << "2 " << n / 2 << endl;
}

B. Gregor and the Pawn Game

  • 题意

给一个棋盘,给出的第一行是敌人的,第二行是自己的,敌人不动,我们自己可以进行两个操作

  1. 当上方的没有敌人的棋子,直接占用即可
  2. 当敌人的棋子在左上或右上的时候,可以选择移至敌人的棋子位子,并吃掉它
  • 思路

贪心, 优先拿左边的,中间的,右边的,记录一下是否用过即可

code :

char a[N], b[N];
bool st[N];
void solve(){
    int n;
    cin >> n;
    for(int i = 1;i <= n;i ++ ) st[i] = 0;
    cin >> (a + 1) >> (b + 1);
    int ans = 0;
    for(int i = 1;i <= n;i ++)  {
        if(a[i] == '1') {
            if(b[i - 1] == '1' && !st[i - 1]) ans ++;
            else if(i + 1 <= n && b[i + 1] == '1') {
                ans ++;
                st[i + 1] = 1;
            }
        }else if(b[i] == '1' && !st[i]) {
            ans ++;
            st[i] = 1;
        }
    }
    cout << ans << endl;
}

C. Web of Lies

  • 题意

给出一个图,每个人及一个点,且当前点的权值为它自己的编号(\(w_i = i\)),当一个人相连的另一个人的权值大于他时,他会死,求最后剩下几个人
三种操作

  1. 增加一条边(\(u \to v\))
  2. 删除一条边(\(u \to v\)), 保证存在
  3. 查询当前剩下几个人
  • 思路

建边后,记录每个人相邻的人中有多少个大于他本身的点,那么只有当所有大于他权值的点和他连的边全删了,他才能活,这里用set进行处理删除和增加边的操作,O(logn)

code :


int st[N];

void solve(){
    int n,m;
    cin >> n >> m;
    for(int i = 1;i <= n;i ++) st[i] = 0;
    int ans = n;
    while(m --) {
        int a,b;
        cin >> a >> b;
        if(a > b) swap(a,b);
        if(!st[a]) {
            ans --;
        }
        st[a]++;
    }
    int k;
    cin >> k;
    fep(i,1,k) {
        int op;
        cin >> op;
        if(op == 1) {
            int a,b;
            cin >> a >> b;
            if(a > b) swap(a,b);
            if(!st[a]) {
                ans --;
            }
            st[a]++;
        }else if(op == 2) {
            int a,b;
            cin >> a >> b;
            if(a > b) swap(a,b);
            st[a] --;
            if(!st[a]) ans ++;
        }else {
            cout << ans << endl;
        }
    }
}

D. Integers Have Friends

  • 题意

给出一个长度为 n 的序列,让你求一个最大长度的连续子序列中 \(a_i mod m = a_{i + 1} mod m = ···· a_j mod m\) , (i -> j), 输出最大的长度

  • 思路

发现差分数组中,某个区间的gcd != 1时,那么这个区间是可以的,那么更新答案。
用st表处理区间gcd,双指针处理左右端点 或 枚举左端点二分长度来处理区间都行。

code :

// ST表处理
int lg[N]; // lg函数记录(int)log(i)
int st[30][N]; // st表,计算st[len][l]的最小值的下标
int n;
int a[N], b[N];

// 处理
void buildST() {
    fep(i,2,n - 1) lg[i]=lg[i >> 1] + 1;
    fep(i,1,n - 1) st[0][i] = b[i];
    fep(j,1,lg[n - 1]) // 长度
        for(int i = 1;i < n - (1 << j) + 1;i ++){ // 左端点
            st[j][i] = __gcd(st[j - 1][i],st[j - 1][i + (1 << (j - 1))]);
        }
            
}
int get_(int l,int r) {
    int len = lg[r - l + 1];
    return __gcd(st[len][l],st[len][r - (1 << len) + 1]);
}

void solve(){
    cin >> n;
    fep(i,1,n) cin >> a[i];
    if(n == 1) {
        cout << "1" << endl;
        return;
    }
    fep(i,1,n - 1) b[i] = abs(a[i + 1] - a[i]);
    buildST();
    int ans = 1;
    int j = 1;
    for (int i = 1; i < n; ++i){
        while(j <= i && get_(j,i) == 1) j ++;
        ans = max(ans, i - j + 2);
    }
    cout << ans << endl;
}
posted @ 2021-08-02 11:01  darker_wxl  阅读(120)  评论(0编辑  收藏  举报
window.onload = function(){ $("#live2dcanvas").attr("style","position: fixed; opacity: 0.7; left: 70px; bottom: 0px; z-index: 1; pointer-events: none;") }