【Atcoder】AGC025 C-F简要题解

*C.Interval Game

跳的贪心方式是唯一的,考虑操作的贪心:

一左一右交替跳一定比同侧优——左跳时贪心选右端点最小的,右跳时贪心选左端点最大的。

枚举第一步是左/右跳分别 O ( n ) O(n) O(n)模拟出答案后取 max ⁡ \max max即可。


*D.Choosing Points

数据范围的明示: 4 N 2 → N 2 4N^2 \to N^2 4N2N2
对于每种 D D D,不能同时选的点之间连边,必然构成一张二分图。
两种 D D D,选 1 2 ⋅ 1 2 = 1 4 \frac12·\frac12=\frac 14 2121=41部分的点必然有解,双重染色后找最大的一部分即可。


*E. Walking on a Tree

设每条边被经过次数是 c n t i cnt_i cnti,答案上界= ∑ min ⁡ ( 2 , c n t i ) \sum \min(2,cnt_i) min(2,cnti)

大胆猜想一定能达到上界,一个经典的构造证明:
每次删去一个叶子结点 x x x,若 x x x的父边 c n t ≤ 1 cnt\leq 1 cnt1,则不需要定向处理;否则取出其中两条路径 ( x , y ) , ( x , z ) (x,y),(x,z) (x,y),(x,z),为使答案达到上界强制这条条路径反向,假设两条路径的交为 ( x , a ) (x,a) (x,a),则这一段都达到了上界,剩下需要决策的实际上为 ( y , z ) (y,z) (y,z)这条路径。不断删点,就构造出了一组可行解。


*F.Addition and Andition

暴力模拟可证复杂度线性 系列

从高位到低位每位重复模拟 K K K遍处理: ( 1 , 1 ) (1,1) (1,1)进位时遇到两个数同一位不相同的情况( ( 0 , 1 ) , ( 1 , 0 ) (0,1),(1,0) (0,1),(1,0))直接暴力进位,否则遇到连续的一段 ( 0 , 0 ) (0,0) (0,0)可以直接移过去,因为从低位的影响不会超过高位,所以不会遇到 ( 1 , 1 ) (1,1) (1,1)
栈维护下标从大到小(当前位置)的 ( 0 , 1 ) , ( 1 , 0 ) (0,1),(1,0) (0,1),(1,0),复杂度均摊是线性的(不会证,可以感性理解为每弹两次栈最多只会压入一个数对)

code from sigongzi

#include 
#define fi first
#define se second
#define pii pair
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 2000005
#define mp make_pair
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
struct node {
    int id,par;
}sta[MAXN],tmp[MAXN];
int N,M,K,top,cnt,ns[MAXN],nt[MAXN],as[MAXN],at[MAXN];
char s[MAXN],t[MAXN];
void Solve() {
    read(N);read(M);read(K);
    scanf("%s",s + 1);scanf("%s",t + 1);
    reverse(s + 1,s + N + 1);reverse(t + 1,t + M + 1);
    for(int i = 1 ; i <= N ; ++i) ns[i] = s[i] - '0';
    for(int i = 1 ; i <= M ; ++i) nt[i] = t[i] - '0';
    int T = max(N,M);
    for(int i = T ; i >= 1 ; --i) {
    if(ns[i] == 1 && nt[i] == 1) {
        int op = K,pos = i,x = 3;cnt = 0;
        while(top) {
        if(x == 3) {
            if(op >= sta[top].id - pos) {
            op -= sta[top].id - pos;
            pos = sta[top].id;
            tmp[++cnt] = (node){pos,x ^ sta[top].par};
            x = x & sta[top].par;
            }
            else break;
        }
        else if(x != 0){
            if(sta[top].id == pos + 1) {
            pos = sta[top].id;
            if(x ^ sta[top].par) x = 3;
            else x = x & sta[top].par;
            }
            else break;
        }
        else break;
        --top;
        }
        if(x != 0 && x != 3) {
        ++pos;
        tmp[++cnt] = (node){pos,x};
        }
        else if(x) {
        pos += op;
        as[pos] = at[pos] = 1;
        }
        for(int j = cnt ; j >= 1 ; --j) sta[++top] = tmp[j];
    }
    else {
        if(ns[i] || nt[i]) {
        sta[++top] = (node){i,ns[i] << 1 | nt[i]};
        }
    }
    }
    for(int i = 1 ; i <= top ; ++i) {
    as[sta[i].id] = (sta[i].par >> 1) & 1;
    at[sta[i].id] = sta[i].par & 1;
    }
    int c = T + K;
    while(as[c] == 0) --c;
    for(int i = c ; i >= 1 ; --i) {out(as[i]);}
    enter;
    c = T + K;
    while(at[c] == 0) --c;
    for(int i = c ; i >= 1 ; --i) {out(at[i]);}
    enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

你可能感兴趣的:(妙,结论及推导,二分图匹配,贪心,构造,atcoder)