Loading

Codeforces Round 973 (Div. 2)

C. Password Cracking (C)

若字符串只向一个方向延伸,则一定能通过 \(2n\) 次询问获得结果;可以先向后猜测,当该侧继续添加字符1与0都不符合要求时、说明已经到达字符串末端,继续询问前缀即可。

void solve() {
    int n;
    cin >> n;
    string s = "";
    bool flag = 0;
    while(s.size() < n) {
        if(flag) {
            cout << "? 0" << s << endl; // 似乎endl自带清空缓存区的功能
            int ok;
            cin >> ok;
            if(ok) s = "0" + s;
            else s = "1" + s;
        } else {
            cout << "? " << s << '0' << endl;
            int ok;
            cin >> ok;
            if(ok) s += "0";
            else {
                cout << "? " << s << '1' << endl;
                cin >> ok;
                if(ok) s += "1";
                else flag = 1;
            }
        }
    }
    cout << "! " << s << endl;
}

D. Minimize the Difference (D)

似乎挺典的一道题,虽然vp的时候先写E去了没过

由于每次操作只能对前项减1、后项加1,得到的最终序列一定单调不降。用单调栈维护最终序列中元素的大小与数量,后项出现较小数时依次出栈,即可保证复杂度为 \(O(n)\).(有一说一题解的单调栈写得比我好看多了,呜)

void solve() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    int it = 0;
    for(int i = 1; i <= n; i++) {
        ll sum = a[i];
        int cur = 1;
        while(it && s[it] >= sum / cur) {
            sum += s[it] * cnt[it];
            cur += cnt[it];
            it--;
        }
        if(sum % cur) {
            s[it + 1] = sum / cur, s[it + 2] = sum / cur + 1;
            cnt[it + 1] = cur - (sum % cur), cnt[it + 2] = sum % cur;
            it += 2;
        } else {
            s[it + 1] = sum / cur, cnt[it + 1] = cur;
            it++;
        }
    }
    printf("%lld\n", s[it] - s[1]);
}

另有:lzz用二分过的,明天去学学他的写法)

E. Prefix GCD (E)

使用上一场D题的结论可以很快做出这题,每次贪心地将能够最小化gcd的值换到当前位置上,若gcd已经达到最小值,之后元素顺序对答案没有影响。

void solve() {
    int n;
    scanf("%d", &n);
    int g = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        g = __gcd(g, a[i]);
    }
    sort(a + 1, a + n + 1);
    int cur = 0;
    for(int i = 1; i <= n; i++) {
        int mg = INF, mi;
        for(int j = i; j <= n; j++) {
            int d = __gcd(cur, a[j]);
            if(d < mg) mg = d, mi = j;
        }
        swap(a[i], a[mi]);
        cur = mg;
        if(mg == g) break;
    }
    cur = 0;
    ll ans = 0;
    for(int i = 1; i <= n; i++) {
        cur = __gcd(cur, a[i]);
        ans += cur;
    }
    printf("%lld\n", ans);
}

(虽然上场D题现在还是TLE状态,但至少结论记住了,也算补完了吧

F1. Game in Tree (Easy Version) (F1)

游戏过程可抽象为:Alice和Bob沿 \(1\)\(u\) 的最短路径相向而行,可以选择在任一时刻进入当前节点下与路径不重合的子树,而子树的最大深度是确定的,可以预处理得到。对Alice而言,若当前最大深度与其经过的长度之和已经大于Bob可以选择的路径最大值,进入子树即为必胜态;对Bob同理。若两人一直选择留在路径上,判断相遇时的步数差即可。

// 这题我的代码好难看。。。
vector <int> v[N];
int dep[N], fa[N];
void pre(int f, int i) {
    fa[i] = f, dep[i] = dep[f] + 1;
    for(int t : v[i]) {
        if(t == f) continue;
        pre(i, t);
    }
}
int mx[N], sub[N];
bool on[N];
void dfs(int i) {
    mx[i] = sub[i] = dep[i];
    for(int t : v[i]) {
        if(t == fa[i]) continue;
        dfs(t);
        if(!on[t]) sub[i] = max(sub[i], mx[t]);
        mx[i] = max(mx[i], mx[t]);
    }
}
int len, p[N], sa[N][20], sb[N][20];
int qa(int l, int r) {
    if(l > r) return 0;
    int k = __lg(r - l + 1);
    return max(sa[l][k], sa[r - (1 << k) + 1][k]);
}
int qb(int l, int r) {
    if(l > r) return 0;
    int k = __lg(r - l + 1);
    return max(sb[l][k], sb[r - (1 << k) + 1][k]);
}
void solve() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        v[i].clear();
    }
    for(int i = 1; i < n; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    pre(0, 1);
    int a, b;
    scanf("%d%d", &a, &b);
    len = 0;
    fill(on + 1, on + n + 1, 0);
    for(int i = a; i; i = fa[i]) {
        p[++len] = i, on[i] = 1;
    }
    dfs(1);
    for(int i = 1; i <= len; i++) {
        sa[i][0] = sub[p[i]];
        int d = len - i;
        if(d < i) sa[i][0] = max(sa[i][0], d + (len - d * 2 + 1) / 2);
        sb[i][0] = i + sub[p[i]] - dep[p[i]];
    }
    for(int k = 1; k <= __lg(len); k++) {
        for(int i = 1; i + (1 << k) - 1 <= len; i++) {
            sa[i][k] = max(sa[i][k - 1], sa[i + (1 << k - 1)][k - 1]);
            sb[i][k] = max(sb[i][k - 1], sb[i + (1 << k - 1)][k - 1]);
        }
    }
    for(int i = 1; i <= len / 2; i++) {
        int j = len - i + 1;
        if(sa[j][0] > qb(i, j - 1)) {
            printf("Alice\n");
            return;
        }
        if(i == j - 1) break;
        if(sb[i][0] >= qa(i + 1, j - 1)) {
            printf("Bob\n");
            return;
        }
        if(i == j - 2) break;
    }
    if(len & 1) printf("Alice\n");
    else printf("Bob\n");
}

F2. Game in Tree (Hard Version) (F2)

没看懂,谁来教教我(哭

posted @ 2024-09-25 23:27  Aderose_yr  阅读(6)  评论(0编辑  收藏  举报