Solving AtCoder Beginner Contest 010: A Complete Walkthrough

Problem A

Given a string (S), produce a new string by appending "pp" to (S).

Simply use std::string in C++:

std::string s;
std::cin >> s;
s += "pp";
std::cout << s << "\n";

Problem B

There are (n) flowers with petal counts (a_1, a_2, \dots, a_n). Two counting cycles exist:

  • "like, disugsting"
  • "like, disgusting, like very much"

Your girlfriend picks a flower and one of the cycles. To ensure the result is always "like" or "like very much", you must remove petals so that for every (i): [ (a_i \equiv 1 \pmod 2) \land (a_i \equiv 1 \lor a_i \equiv 0 \pmod 3). ] This simplifies to (a_i \equiv 1 \pmod 6) or (a_i \equiv 3 \pmod 6).

O((n)) brute force:

int c = 0;
for (int i = 0; i < n; ++i) {
    int x; std::cin >> x;
    while (x % 6 != 1 && x % 6 != 3 && x > 0) {
        --x;
        ++c;
    }
}
std::cout << c << "\n";

A constant-time version using integer division:

i64 floordiv(i64 a, i64 b) {
    if (a % b == 0) return a / b;
    else if ((a ^ b) > 0) return a / b;
    else return a / b - 1;
}

void solve() {
    int n; std::cin >> n;
    i64 c = 0;
    for (int i = 0; i < n; ++i) {
        i64 x; std::cin >> x;
        i64 p1 = floordiv(x - 1, 6) * 6 + 1;
        i64 p2 = floordiv(x - 3, 6) * 6 + 3;
        i64 p = std::max({0LL, p1, p2});
        c += x - p;
    }
    std::cout << c << "\n";
}

Solving congruences: For a system [ \begin{cases} X \equiv a \pmod b \ X \equiv c \pmod d \end{cases} ] we combine by solving (a + bx = c + dy), which gives (x = x_0 + \frac{d}{(b,d)}t) and [ X \equiv a + b x_0 \pmod{[b,d]}. ] We can iterate to combine (n) congruences.

To solve (ax + by = p), if ((a,b)\mid p), reduce to (a'x + b'y = p'). Solve (a'x' + b'y' = 1) via extended Euclidean algorithm, then (x_0 = x' \cdot p' \bmod b').

The extended Euclidean algorithm:

def extended_gcd(a, b):
    if b == 0:
        return (1, 0, a)
    else:
        x1, y1, g = extended_gcd(b, a % b)
        return (y1, x1 - (a // b) * y1, g)

Problem C

Start ((sx,sy)), end ((tx,ty)), (T) minutes, speed (V), (n) intermediate points. Check if any intermeidate point allows reaching within (T\cdot V): [ \sqrt{(sx-x_i)^2+(sy-y_i)^2}+\sqrt{(tx-x_i)^2+(ty-y_i)^2} \le T\cdot V. ] Use a small epsilon to avoid floating point errors:

const double EPS = 1e-9;

int dist2(int x1, int y1, int x2, int y2) {
    return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

void solve() {
    int sx,sy,tx,ty; std::cin >> sx >> sy >> tx >> ty;
    int T,V; std::cin >> T >> V;
    int n; std::cin >> n;
    bool ok = false;
    while (n--) {
        int x,y; std::cin >> x >> y;
        double d = std::sqrt(dist2(sx,sy,x,y)) + std::sqrt(dist2(x,y,tx,ty));
        if (d - T*V < EPS) ok = true;
    }
    std::cout << (ok ? "YES" : "NO") << "\n";
}

Alternatively, check ellipse containment without floating point by squaring, but the above is simpler for contest.

Problem D

Undirected graph with (n) nodes (0 = you). You can talk to people you meet; meeting propagates through friends. Girlfriend can:

  • Delete an edge (cut friendship)
  • Delete a node (forbid a person to talk to you, but they still connect others)

Goal: disconnect all "girl" nodes (input given) from node 0 with minimum operations.

This is a minimum cut problem. Construct flow network:

  • Source (s = n+1), sink (t = n+2).
  • For edges from source (node 0): add directed edge (s \to v) with capacity 1 (because cutting this edge corresponds to deleting the friendship).
  • For other edges: add undirected edge with capacity 1.
  • For each girl node (g): add edge (g \to t) with capacity 1 (cutting this edge means forbidding that person).

Minimum cut = maximum flow (Dinic). Complexity (O(n^2 m) = O(n^4)).

// Dinic implementation
template<typename T, int V=110, int E=2010>
struct FlowGraph {
    int s,t,vtot;
    int head[V],etot;
    int dist[V],cur[V];
    struct Edge { int v,nxt; T f; } e[E*2];

    void init(int _s,int _t,int _vtot) {
        s=_s; t=_t; vtot=_vtot;
        for(int i=1;i<=vtot;++i) head[i]=-1;
        etot=0;
    }
    void add_edge(int u,int v,T f1,T f2=0) {
        e[etot]={v,head[u],f1}; head[u]=etot++;
        e[etot]={u,head[v],f2}; head[v]=etot++;
    }
    bool bfs() {
        for(int i=1;i<=vtot;++i) dist[i]=0,cur[i]=head[i];
        std::queue<int> q; q.push(s); dist[s]=1;
        while(!q.empty()) {
            int u=q.front(); q.pop();
            for(int i=head[u];~i;i=e[i].nxt) if(e[i].f && !dist[e[i].v]) {
                int v=e[i].v; dist[v]=dist[u]+1;
                if(v==t) return true;
                q.push(v);
            }
        }
        return false;
    }
    T dfs(int u,T flow) {
        if(u==t) return flow;
        T used=0;
        for(int &i=cur[u];~i;i=e[i].nxt) if(e[i].f && dist[e[i].v]==dist[u]+1) {
            int v=e[i].v;
            T f=dfs(v,std::min(flow-used,e[i].f));
            e[i].f-=f; e[i^1].f+=f;
            used+=f;
            if(used==flow) break;
        }
        if(!used) dist[u]=-1;
        return used;
    }
    T dinic() {
        T flow=0;
        while(bfs()) flow+=dfs(s,std::numeric_limits<T>::max());
        return flow;
    }
};

FlowGraph<int> g;

void solve() {
    int N,G,E; std::cin >> N >> G >> E;
    int s=N+1, t=N+2;
    g.init(s,t,N+2);
    for(int i=0;i<G;++i) {
        int x; std::cin >> x;
        g.add_edge(x,t,1);
    }
    for(int i=0;i<E;++i) {
        int u,v; std::cin >> u >> v;
        if(u>v) std::swap(u,v);
        if(u==0) g.add_edge(s,v,1,1);
        else g.add_edge(u,v,1,1);
    }
    std::cout << g.dinic() << "\n";
}

Variations:

  • If only edge deletion allowed: collapse all girl nodes into one, then min cut.
  • If different costs for node/edge deletion: split each node into in/out with weight, use standard node-splitting technique.

Tags: AtCoder ABC010 flow min-cut congruence

Posted on Tue, 06 Oct 2026 16:11:29 +0000 by mauri_gato