Skip to content

Final exam prep

DJ set

food chain
#include <iostream>
using namespace std;

const int maxn = 50005;
const int inf = 0x3f3f3f3f;

int N, K;
int p[maxn], w[maxn];

void init(int N) {
    for (int i = 0; i <= N; i++) {
        p[i] = i;
        w[i] = 0;
    }
}

int par(int x) {
    if (p[x] == x) return x;
    int fx = p[x];
    p[x] = par(fx);
    w[x] = (w[x] + w[fx]) % 3;
    return p[x];
}

void merge(int x, int y, int d) {
    int fx = par(x);
    int fy = par(y);
    p[fx] = fy;
    w[fx] = (d - 1 + w[y] - w[x] + 3) % 3;
}

int ans, d, x, y;

int main() {
    cin >> N >> K;
    init(N);
    ans = 0;
    for (int i = 0; i < K; i++) {
        cin >> d >> x >> y;
        if (x > N || y > N) {
            ans++;
            continue;
        }
        if (par(x) != par(y)) merge(x, y, d);
        else {
            if (d == 1) {
                if (w[x] == w[y]) continue;
                else ans++;
            }
            else {
                if ((w[x] - w[y] + 3) % 3 == 1) continue;
                else ans++;
            }
        }
    }
    cout << ans << endl;
};
cube stacking
#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <bitset>
using namespace std;

const int maxn = 30005;

int N, M;
int p[maxn], sum[maxn], under[maxn];

void init(int N) {
    for (int i = 1; i <= N; i++) {
        p[i] = i;
        sum[i] = 1;
        under[i] = 0;
    }
}

int par(int x) {
    if (p[x] == x) return x;
    int f = p[x];
    p[x] = par(f);
    under[x] += under[f];
    return p[x];
}

void merge(int x, int y) {
    int fx = par(x);
    int fy = par(y);
    p[fy] = fx;
    under[fy] = sum[fx];
    sum[fx] += sum[fy];
}

char c;
int x, y;

int main() {
    init(maxn);
    cin >> M;
    for (int i = 0; i < M; i++) {
        cin >> c;
        if (c == 'C') {
            cin >> x;
            par(x);
            cout << under[x] << endl;
        }
        else {
            cin >> x >> y;
            merge(y, x);
        }
    }
}
the suspects
#include <iostream>
using namespace std;

const int maxn = 30005;
const int inf = 0x3f3f3f3f;

int N, M;
int p[maxn];

void init(int N) {
    for (int i = 0; i < N; i++) {
        p[i] = i;
    }
}

int par(int x) {
    if (p[x] == x) return x;
    int fx = p[x];
    p[x] = par(fx);
    return p[x];
}

void merge(int x, int y) {
    int fx = par(x);
    int fy = par(y);
    p[fx] = fy;
}

int ans, x, y, z;

int main() {
    while (cin >> N >> M && N) {
        init(N);
        for(int i = 0; i < M; i++) {
            cin >> x >> y;
            for (int i = 1; i < x; i++) {
                cin >> z;
                if (par(y) != par(z)) merge(y, z);
            }
        }
        ans = 0;
        int tmp = par(0);
        for (int i = 0; i < N; i++) {
            if (par(i) == tmp) ans++;
        }
        cout << ans << endl;
    }
}

BIT

apple tree
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

const int maxn = 100005;
int N;

int arr[maxn], bit[maxn], in[maxn], out[maxn];
vector<int> G[maxn];

int lowbit(int x) { return x & (-x); }

void add(int i, int x) {
    arr[i] += x;
    for (i; i <= N; i+=lowbit(i)) bit[i] += x;
}

int query(int i) {
    int ans = 0;
    for (i; i > 0; i -= lowbit(i)) ans += bit[i];
    return ans;
}

int t;
void dfs(int x) {
    in[x] = t++;
    for (int i = 0; i < G[x].size(); i++) dfs(G[x][i]);
    out[x] = t;
}

int M, x, y;
char c;

int main() {
    cin >> N;
    memset(arr, 0, sizeof(arr));
    memset(bit, 0, sizeof(bit));
    for (int i = 1; i <= N; i++) add(i, 1);
    for (int i = 1; i < N; i++) {
        cin >> x >> y;
        G[x].push_back(y);
    }
    t = 0;
    dfs(1);
    cin >> M;
    for (int i = 0; i < M; i++) {
        cin >> c >> x;
        if (c == 'Q') cout << query(out[x]) - query(in[x]) << endl;
        else {
            int p = in[x] + 1;
            add(p, (arr[p] ? -1 : 1));
        }
    }
}
LIS(NlgN BS+DP)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn = 300005;
const int inf = 0x7fffffff;
int N;
int arr[maxn], dp[maxn];

int main() {
    scanf("%d", &N);
    for (int i = 0; i < N; i++) scanf("%d", arr + i);
    for (int i = 0; i < N; i++) dp[i] = inf;
    int ans = 0;
    for (int i = 0; i < N; i++) {
        int idx = lower_bound(dp, dp + N, arr[i]) - dp;
        dp[idx] = arr[i];
        if (idx == ans) ans++;
    }
    cout << ans << endl;
}

Segment Tree

Balanced Lineup

静态求区间最值。

cin就算了,没想到这个题cout都卡。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define P pair<int,int>
#define lc rt*2+1
#define rc rt*2+2
using namespace std;

const int maxn = 50005;
const int inf = 0x7fffffff;
int h[maxn];
int N, Q;

struct node {
    int l, r;
    int mx, mn;
    int m() { return (l + r) / 2; }
} tr[maxn*4];

void build(int rt, int l, int r) {
    tr[rt].l = l;
    tr[rt].r = r;
    if (l == r) {
        tr[rt].mx = tr[rt].mn = h[l];
        return;
    }
    int m = (l + r) / 2;
    build(lc, l, m);
    build(rc, m + 1, r);
    tr[rt].mx = max(tr[lc].mx, tr[rc].mx);
    tr[rt].mn = min(tr[lc].mn, tr[rc].mn);
}

int mx, mn;
void query(int rt, int l, int r) {
    if (l == tr[rt].l && r == tr[rt].r) {
        mx = max(mx, tr[rt].mx);
        mn = min(mn, tr[rt].mn);
        return;
    }
    int m = tr[rt].m();
    if (r <= m) query(lc, l, r);
    else if (l > m) query(rc, l, r);
    else {
        query(lc, l, m);
        query(rc, m + 1, r);
    }
}

int x, y;

int main() {
    scanf("%d%d", &N, &Q);
    for (int i = 0; i < N; i++) scanf("%d", h + i);
    build(0, 0, N - 1);
    for (int i = 0; i < Q; i++) {
        scanf("%d%d", &x, &y);
        mn = inf, mx = 0;
        query(0, x - 1, y - 1);
        printf("%d\n", mx - mn);
    }
}
integers
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;

#define ll long long

const int maxn = 100005;
ll arr[maxn];
int N, Q;

struct node {
    int l, r;
    ll sum, inc;
    int mid() { return (l + r) / 2; }
} tr[maxn<<2];

#define lc 2*rt+1
#define rc 2*rt+2

void pushup(int rt) {
    tr[rt].sum = tr[lc].sum + tr[rc].sum;
}

void pushdown(int rt) {
    if (tr[rt].inc) {
        tr[rt].sum += (tr[rt].r - tr[rt].l + 1)*tr[rt].inc;
        tr[lc].inc += tr[rt].inc;
        tr[rc].inc += tr[rt].inc;
        tr[rt].inc = 0;
    }
}

void build(int rt, int l, int r) {
    tr[rt].l = l;
    tr[rt].r = r;
    tr[rt].inc = 0;
    if (l == r) {
        tr[rt].sum = arr[l];
        return;
    }
    int m = (l + r) / 2;
    build(lc, l, m);
    build(rc, m + 1, r);
    pushup(rt);
}


void add(int rt, int l, int r, int v) {
    if (tr[rt].l == l && tr[rt].r == r) {
        tr[rt].inc += v;
        return;
    }
    tr[rt].sum += (r - l + 1)*v;
    int m = tr[rt].mid();
    if (l > m) add(rc, l, r, v);
    else if (r <= m) add(lc, l, r, v);
    else {
        add(lc, l, m, v);
        add(rc, m + 1, r, v);
    }
}


ll query(int rt, int l, int r) {
    if (tr[rt].l == l && tr[rt].r == r) return tr[rt].sum + tr[rt].inc*(r - l + 1);
    pushdown(rt);
    int m = tr[rt].mid();
    if (l > m) return query(rc, l, r);
    else if (r <= m) return query(lc, l, r);
    else return query(lc, l, m) + query(rc, m + 1, r);
}

char c;
int a, b, d;

int main() {
    cin >> N >> Q;
    for (int i = 0; i < N; i++) cin >> arr[i];
    build(0, 0, N - 1);
    for (int i = 0; i < Q; i++) {
        cin >> c;
        if (c == 'Q') {
            cin >> a >> b;
            cout << query(0, a-1, b-1) << endl;
        }
        else {
            cin >> a >> b >> d;
            add(0, a-1, b-1, d);
        }
    }
}
kth-Number
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <map>
#include <iomanip>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;

const int maxn = 100005;
int N;
int arr[maxn];

#define lc 2*rt+1
#define rc 2*rt+2

struct node {
    int l, r;
    vector<int> v;
    int m() { return (l + r) / 2; }
} tr[maxn<<2];

void pushup(int rt) {
    vector<int>& a = tr[lc].v;
    vector<int>& b = tr[rc].v;
    vector<int>& c = tr[rt].v;
    c.resize(a.size() + b.size()); // necessary
    merge(a.begin(), a.end(), b.begin(), b.end(), c.begin());
}

void build(int rt, int l, int r) {
    tr[rt].l = l;
    tr[rt].r = r;
    if (l == r) {
        tr[rt].v.push_back(arr[l]);
        return;
    }
    int m = (l + r) / 2;
    build(lc, l, m);
    build(rc, m + 1, r);
    pushup(rt);
}

int query(int rt, int l, int r, int v) {
    if (tr[rt].l == l && tr[rt].r == r) {
        return upper_bound(tr[rt].v.begin(), tr[rt].v.end(), v) - tr[rt].v.begin();
    }
    int m = tr[rt].m();
    if (l > m) return query(rc, l, r, v);
    else if (r <= m) return query(lc, l, r, v);
    else return query(lc, l, m, v) + query(rc, m + 1, r, v);
}

void solve(int l, int r, int k) {
    int left = -1e9 - 1, right = 1e9 + 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (query(0, l, r, mid) < k) left = mid + 1;
        else right = mid;
    }
    cout << left << endl;
}

int Q, a, b, c;

int main() {
    cin.sync_with_stdio(false);
    cin >> N >> Q;
    for (int i = 0; i < N; i++) cin >> arr[i];
    build(0, 0, N - 1);
    for (int i = 0; i < Q; i++) {
        cin >> a >> b >> c;
        solve(a - 1, b - 1, c);
    }
}
Mayor's Poster
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <map>
#include <iomanip>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;

const int maxn = 10005;
int p[maxn][2];
int N;

struct node {
    int l, r;
    bool occ;
    int mid() { return (l + r) / 2; }
} tr[maxn*8];

#define lc 2*rt+1
#define rc 2*rt+2

void pushup(int rt) {
    tr[rt].occ = tr[lc].occ & tr[rc].occ;
}

void pushdown(int rt) {
    if (tr[rt].occ) {
        tr[lc].occ = 1;
        tr[rc].occ = 1;
    }
}

void build(int rt, int l, int r) {
    tr[rt].l = l;
    tr[rt].r = r;
    tr[rt].occ = 0;
    if (l == r) return;
    int m = tr[rt].mid();
    build(lc, l, m);
    build(rc, m + 1, r);
}

bool add(int rt, int l, int r) {
    if (tr[rt].l == l && tr[rt].r == r) {
        if (tr[rt].occ == 0) {
            tr[rt].occ = 1;
            return true;
        }
        else return false;
    }
    pushdown(rt);
    int m = tr[rt].mid();
    bool flag;
    if (l > m) flag = add(rc, l, r);
    else if (r <= m) flag = add(lc, l, r);
    else flag = add(lc, l, m) | add(rc, m + 1, r);
    pushup(rt);
    return flag;
}

int main() {
    int cas;
    cin >> cas;
    while (cas--) {
        cin >> N;
        vector<int> xs;
        map<int, int> m;
        for (int i = 0; i < N; i++) {
            cin >> p[i][0] >> p[i][1];
            xs.push_back(p[i][0]);
            xs.push_back(p[i][1]);
        }
        sort(xs.begin(), xs.end());
        int uN = unique(xs.begin(), xs.end()) - xs.begin();
        for (int i = 0; i < uN; i++) m[xs[i]] = i;
        build(0, 0, uN - 1);
        int ans = 0;
        for (int i = N - 1; i >= 0; i--) {
            if (add(0, m[p[i][0]], m[p[i][1]])) 
                ans++;
        }
        cout << ans << endl;
    }
}

Trie

Proto
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
#define ll long long

using namespace std;

const int maxc = 26;

struct node {
    node* cs[maxc];
    node* fail;
    bool bad;
    node() {
        fail = 0;
        memset(cs, 0, sizeof(cs));
        bad = false;
    }
};

void insert(node* rt, string s) {
    for (int i = 0; i < s.size(); i++) {
        int idx = s[i] - 'a';
        if (!rt->cs[idx]) rt->cs[idx] = new node();
        rt = rt->cs[idx];
    }
    rt->bad = true;
}

void build(node* rt) {
    node* rrt = new node();
    rt->fail = rrt;
    for (int i = 0; i < maxc; i++) rrt->cs[i] = rt;
    queue<node*> q;
    q.push(rt);
    while (!q.empty()) {
        node* p = q.front(); q.pop();
        for (int i = 0; i < maxc; i++) {
            node* pc = p->cs[i];
            if (pc) {
                node* pre = p->fail; // father's fail
                while (!pre->cs[i]) pre = pre->fail;
                pc->fail = pre->cs[i];
                if (pc->fail->bad) pc->bad = true;
                q.push(pc);
            }
        }
    }
}

bool match(node* rt, string s) {
    node* p = rt;
    for (int i = 0; i < s.size(); i++) {
        int idx = s[i] - 'a';
        while (p != rt && !p->cs[idx]) p = p->fail; // back tracing first
        if (p->cs[idx]) {
            p = p->cs[idx]; // move
            if (p->bad) return true;
        }
        else continue;  // fail anyway
    }
    return false;
}

int N, M;
string s;

int main() {
    cin >> N;
    node* root = new node();
    for (int i = 0; i < N; i++) {
        cin >> s;
        insert(root, s);
    }
    build(root); // don't forget
    cin >> M;
    for (int i = 0; i < M; i++) {
        cin >> s;
        if (match(root, s)) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
}

Directed Tarjan

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define P pair<int,int>

using namespace std;

// 4:53

const int maxn = 10005;
int N, M;

struct edge {
    int f, t;
    edge() {}
    edge(int f, int t) :f(f), t(t) {}
};

vector<edge> G[maxn];

int dfn[maxn], low[maxn], vis[maxn], color[maxn], outd[maxn];
int idx, ncol;
stack<int> stk;

void tarjan(int s) {
    dfn[s] = low[s] = idx++;
    vis[s] = 1;
    stk.push(s);
    for (int i = 0; i < G[s].size(); i++) {
        int t = G[s][i].t;
        if (!vis[t]) {
            tarjan(t);
            low[s] = min(low[s], low[t]);
        }
        else if (vis[t] == 1) {
            low[s] = min(low[s], dfn[t]);
        }
    }
    if (low[s] == dfn[s]) {
        int t;
        do {
            t = stk.top(); stk.pop();
            color[t] = ncol;
            vis[t] = 2;
        } while (t != s);
        ncol++;
    }
}

int solve() {
    memset(vis, 0, sizeof(vis));
    memset(outd, 0, sizeof(outd));
    memset(color, -1, sizeof(color));
    // check un-connectivity
    for (int i = 1; i <= N; i++) { 
        if (!vis[i]) tarjan(i);
    }
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j < G[i].size(); j++) {
            edge& e = G[i][j];
            if (color[e.t] != color[e.f]) {
                outd[color[e.f]] ++;
            }
        }
    }
    int res = -1;
    for (int i = 0; i < ncol; i++) {
        if (outd[i] == 0) {
            if (res == -1) res = i;
            else return 0;
        }
    }
    int cnt = 0;
    for (int i = 1; i <= N; i++) {
        if (color[i] == res) cnt++;
    }
    return cnt;
}

int x, y;

int main() {
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> x >> y;
        G[x].push_back(edge(x, y));
    }
    cout << solve() << endl;
}

// 5:08

Shortest Path

candies
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define P pair<int,int>

using namespace std;

const int maxn = 30100;
const int inf = 0x3f3f3f3f;
int N, M;

struct edge {
    int f, t, w;
    edge() {}
    edge(int f, int t, int w) :f(f), t(t), w(w) {}
};

vector<edge> G[maxn];

int dist[maxn];

void dijstra(int s) {
    fill(dist, dist + N + 1, inf);
    dist[s] = 0;
    priority_queue<P, vector<P>, greater<P>> q;
    q.push(make_pair(dist[s], s));
    while (!q.empty()) {
        P p = q.top(); q.pop();
        int v = p.second;
        if (dist[v] != p.first) continue; // vis
        for (int i = 0; i < G[v].size(); i++) {
            edge& e = G[v][i];
            if (dist[e.t] > dist[e.f] + e.w) {
                dist[e.t] = dist[e.f] + e.w;
                q.push(make_pair(dist[e.t], e.t));
            }
        }
    }
}

/*
int dijstra(int s, int t) {
    fill(dist, dist + N + 1, inf);
    dist[s] = 0;
    priority_queue<P, vector<P>, greater<P>> q;
    q.push(make_pair(dist[s], s));
    while (!q.empty()) {
        P p = q.top(); q.pop();
        int v = p.second;
        if (dist[v] < p.first) continue;
        if (v == t) return dist[v]; // return after check !!!
        for (int i = 0; i < G[v].size(); i++) {
            edge& e = G[v][i];
            if (dist[e.t] > dist[e.f] + e.w) {
                dist[e.t] = dist[e.f] + e.w;
                q.push(make_pair(dist[e.t], e.t));
            }
        }
    }
    return -1;
}
*/

int x, y, w;

int main() {
    scanf("%d%d", &N, &M);
    for (int i = 0; i < M; i++) {
        scanf("%d%d%d", &x, &y, &w);
        G[x].push_back(edge(x, y, w));
    }
    dijstra(1);
    printf("%d\n", dist[N]);
}
currency exchange
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define P pair<int,int>

using namespace std;

const int maxn = 105;
int N, M;

struct edge {
    int f, t;
    double r, c;
    edge() {}
    edge(int f, int t, double r, double c) :f(f), t(t), r(r), c(c) {}
};

vector<edge> G[maxn];

int s;
double v;
double dist[maxn];

bool bf() {
    memset(dist, 0, sizeof(dist));
    dist[s] = v;
    for (int k = 1; k < N; k++) {
        bool flag = true;
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j < G[i].size(); j++) {
                edge& e = G[i][j];
                if (dist[e.t] < (dist[e.f] - e.c) * e.r) {
                    dist[e.t] = (dist[e.f] - e.c) * e.r;
                    flag = false;
                }
            }
        }
        if (flag) return false;
    }
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j < G[i].size(); j++) {
            edge& e = G[i][j];
            if (dist[e.t] < (dist[e.f] - e.c)*e.r) return true;
        }
    }
    return false;
}

int x, y;
double a, b, c, d;

int main() {
    cin >> N >> M >> s >> v;
    for (int i = 0; i < M; i++) {
        cin >> x >> y >> a >> b >> c >> d;
        G[x].push_back(edge(x, y, a, b));
        G[y].push_back(edge(y, x, c, d));
    }
    cout << (bf() ? "YES" : "NO") << endl;
}
Warmholes
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define P pair<int,int>

using namespace std;

const int maxn = 505;
const int inf = 0x3f3f3f3f;
int N, M, W;

struct edge {
    int f, t, w;
    edge() {}
    edge(int f, int t, int w) :f(f), t(t), w(w) {}
};

vector<edge> G[maxn];

int dist[maxn], times[maxn];

bool spfa(int s) {
    fill(dist, dist + N + 1, inf);
    fill(times, times + N + 1, 0);
    dist[s] = 0;
    //queue<int> q;
    stack<int> q;
    q.push(s);
    while (!q.empty()) {
        //int p = q.front(); q.pop();
        int p = q.top(); q.pop();
        for (int i = 0; i < G[p].size(); i++) {
            edge& e = G[p][i];
            if (dist[e.t] > dist[e.f] + e.w) {
                dist[e.t] = dist[e.f] + e.w;
                q.push(e.t);
                if (times[e.t]++ >= N) return true;
            }
        }
    }
    return false;
}

int T, x, y, w;

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d", &N, &M, &W);
        for (int i = 1; i <= N; i++) G[i].clear();
        for (int i = 0; i < M; i++) {
            scanf("%d%d%d", &x, &y, &w);
            G[x].push_back(edge(x, y, w));
            G[y].push_back(edge(y, x, w));
        }
        for (int i = 0; i < W; i++) {
            scanf("%d%d%d", &x, &y, &w);
            G[x].push_back(edge(x, y, -w));
        }
        cout << (spfa(1) ? "YES" : "NO") << endl;
    }
}
cow contest
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define P pair<int,int>

using namespace std;

const int maxn = 105;
const int inf = 0x3f3f3f3f;
int N, M, W;

struct edge {
    int f, t;
    edge() {}
    edge(int f, int t) :f(f), t(t) {}
};

vector<edge> G[maxn];

int dist[maxn][maxn];

void floyd() {
    memset(dist, 0x3f, sizeof(dist));
    for (int i = 1; i <= N; i++) {
        dist[i][i] = 0;
        for (int j = 0; j < G[i].size(); j++) {
            edge& e = G[i][j];
            dist[e.f][e.t] = 1;
        }
    }
    for (int k = 1; k <= N; k++) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (dist[i][j] > dist[i][k] + dist[k][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
}


int T, x, y;

int main() {
    while (~scanf("%d%d", &N, &M)) {
        for (int i = 1; i <= N; i++) G[i].clear();
        for (int i = 0; i < M; i++) {
            scanf("%d%d", &x, &y);
            G[x].push_back(edge(x, y));
        }
        floyd();
        int ans = 0;
        for (int i = 1; i <= N; i++) {
            int cnt = 0;
            for (int j = 1; j <= N; j++) {
                if (j == i) continue;
                if (dist[i][j] != inf) cnt++;
                if (dist[j][i] != inf) cnt++;
            }
            if (cnt == N - 1) ans++;
        }
        cout << ans << endl;
    }
}

Undirected Tarjan

···

Maximum Flow

Alice's Chance

build the graph...

#include <iostream>    
#include <cstring>
#include <queue>   
#include <vector>  
#include <algorithm>   
#include <deque>   
#define inf 999999999

using namespace std;

const int maxn = 400;

int G[maxn][maxn];
bool vis[maxn];
int Layer[maxn];   //Layer[i]是节点i的层号  
int M = 371;

bool CountLayer(int src, int dst) { //分层
    int layer = 0;
    deque<int>q;
    memset(Layer, 0xff, sizeof(Layer)); //都初始化成-1
    Layer[src] = 0;
    q.push_back(src);
    while (!q.empty()) {
        int v = q.front();
        q.pop_front();
        for (int j = 1; j <= M; j++) {
            if (G[v][j] > 0 && Layer[j] == -1) {
                //Layer[j] == -1 说明j还没有访问过
                Layer[j] = Layer[v] + 1;
                if (j == dst) return true;  //分层到汇点即可
                else q.push_back(j);
            }
        }
    }
    return false;
}
int Dinic(int src, int dst) {
    int i;
    int s;
    int nMaxFlow = 0;
    deque<int> q; //DFS用的栈
    while (CountLayer(src, dst)) { //只要能分层
        q.push_back(src);   //源点入栈  
        memset(vis, 0, sizeof(vis));
        vis[src] = 1;
        while (!q.empty()) {
            int nd = q.back();
            if (nd == dst) { // nd是汇点
                //在栈中找容量最小边
                int nMinC = inf;
                int nMinC_vs; //容量最小边的起点
                for (i = 1; i < q.size(); i++) {
                    int vs = q[i - 1];
                    int ve = q[i];
                    if (G[vs][ve] > 0) {
                        if (nMinC > G[vs][ve]) {
                            nMinC = G[vs][ve];
                            nMinC_vs = vs;
                        }
                    }
                }
                //增广,改图
                nMaxFlow += nMinC;
                for (i = 1; i < q.size(); i++) {
                    int vs = q[i - 1];
                    int ve = q[i];
                    G[vs][ve] -= nMinC; //修改边容量 
                    G[ve][vs] += nMinC; //添加反向边
                }
                //退栈到 nMinC_vs成为栈顶,以便继续dfs
                while (!q.empty() && q.back() != nMinC_vs) {
                    vis[q.back()] = 0;
                    q.pop_back();
                }

            }
            else { //nd不是汇点
                for (i = 1; i <= M; i++) {
                    if (G[nd][i] > 0 && Layer[i] == Layer[nd] + 1 &&
                        !vis[i]) {
                        //只往下一层的没有走过的节点走
                        vis[i] = 1;
                        q.push_back(i);
                        break;
                    }
                }
                if (i > M)  //找不到下一个点
                    q.pop_back(); //回溯
            }
        }
    }
    return nMaxFlow;
}

const int maxk = 25;
int movies[maxk][10];

int T, K;
int src = 0, dst = 371;

void build() {
    for (int i = 1; i <= 350; i++) G[src][i] = 1;
    for (int k = 0; k < K; k++) {
        int tmp = 351 + k;
        for (int j = 1; j <= movies[k][8] * 7; j++) {
            if (movies[k][(j - 1) % 7]) {
                G[j][tmp] = 1;
            }
        }
        G[tmp][dst] = movies[k][7];
    }
}

int main() {
    cin >> T;
    while (T--) {
        cin >> K;
        int tot = 0;
        for (int i = 0; i < K; i++) {
            for (int j = 0; j < 9; j++) {
                cin >> movies[i][j];
            }
            tot += movies[i][7];
        }
        memset(G, 0, sizeof(G));
        build();
        int ans = Dinic(src, dst);
        if (ans == tot) cout << "Yes" << endl;
        else cout << "No" << endl;
    }
}
Asteroids

bipartite

#include <iostream>    
#include <cstring>
#include <queue>   
#include <vector>  
#include <algorithm>   
#include <deque>   
#define inf 999999999

using namespace std;

const int maxn = 2000;

int G[maxn][maxn];
bool vis[maxn];
int Layer[maxn];   //Layer[i]是节点i的层号  
int M;

bool CountLayer(int src, int dst) { //分层
    int layer = 0;
    deque<int>q;
    memset(Layer, 0xff, sizeof(Layer)); //都初始化成-1
    Layer[src] = 0;
    q.push_back(src);
    while (!q.empty()) {
        int v = q.front();
        q.pop_front();
        for (int j = 1; j <= M; j++) {
            if (G[v][j] > 0 && Layer[j] == -1) {
                //Layer[j] == -1 说明j还没有访问过
                Layer[j] = Layer[v] + 1;
                if (j == dst) return true;  //分层到汇点即可
                else q.push_back(j);
            }
        }
    }
    return false;
}
int Dinic(int src, int dst) {
    int i;
    int s;
    int nMaxFlow = 0;
    deque<int> q; //DFS用的栈
    while (CountLayer(src, dst)) { //只要能分层
        q.push_back(src);   //源点入栈  
        memset(vis, 0, sizeof(vis));
        vis[src] = 1;
        while (!q.empty()) {
            int nd = q.back();
            if (nd == dst) { // nd是汇点
                //在栈中找容量最小边
                int nMinC = inf;
                int nMinC_vs; //容量最小边的起点
                for (i = 1; i < q.size(); i++) {
                    int vs = q[i - 1];
                    int ve = q[i];
                    if (G[vs][ve] > 0) {
                        if (nMinC > G[vs][ve]) {
                            nMinC = G[vs][ve];
                            nMinC_vs = vs;
                        }
                    }
                }
                //增广,改图
                nMaxFlow += nMinC;
                for (i = 1; i < q.size(); i++) {
                    int vs = q[i - 1];
                    int ve = q[i];
                    G[vs][ve] -= nMinC; //修改边容量 
                    G[ve][vs] += nMinC; //添加反向边
                }
                //退栈到 nMinC_vs成为栈顶,以便继续dfs
                while (!q.empty() && q.back() != nMinC_vs) {
                    vis[q.back()] = 0;
                    q.pop_back();
                }

            }
            else { //nd不是汇点
                for (i = 1; i <= M; i++) {
                    if (G[nd][i] > 0 && Layer[i] == Layer[nd] + 1 &&
                        !vis[i]) {
                        //只往下一层的没有走过的节点走
                        vis[i] = 1;
                        q.push_back(i);
                        break;
                    }
                }
                if (i > M)  //找不到下一个点
                    q.pop_back(); //回溯
            }
        }
    }
    return nMaxFlow;
}

int src, dst;
int N, K, x, y;

int main() {
    cin >> N >> K;
    M = 2 * N + 1;
    memset(G, 0, sizeof(G));
    src = 0;
    dst = 2 * N + 1;
    for (int i = 1; i <= N; i++) G[src][i] = 1;
    for (int i = N + 1; i <= 2 * N; i++) G[i][dst] = 1;
    for (int i = 0; i < K; i++) {
        cin >> x >> y;
        G[x][y+N] = inf;
    }
    cout << Dinic(src, dst) << endl;
}

Geometry

TOYS
#include <iostream>    
#include <cstring>
#include <string>
#include <queue>   
#include <vector>  
#include <algorithm>   
#include <deque>   

using namespace std;

double PI = acos(-1);
double INF = 1e20;
double EPS = 1e-3;

bool IsZero(double x) {
    return -EPS < x && x < EPS;
}
bool FLarger(double a, double b) {
    return a - b > EPS;
}
bool FLess(double a, double b) {
    return b - a > EPS;
}

struct CVector {
    double x, y;
    CVector() {}
    CVector(double x, double y) :x(x), y(y) {}
};

typedef CVector CPoint;

struct CLine {
    CPoint a, b;
    CLine() {}
    CLine(CPoint a, CPoint b) :a(a), b(b) {}
};

CVector operator +(CVector p, CVector q) {
    return CVector(p.x + q.x, p.y + q.y);
}

CVector operator -(CVector p, CVector q) {
    return CVector(p.x - q.x, p.y - q.y);
}

CVector operator *(double k, CVector p) {
    return CVector(k * p.x, k * p.y);
}

CVector operator /(CVector p, double k) {
    return CVector(p.x / k, p.y / k);
}

double operator *(CVector p, CVector q) {
    return p.x * q.x + p.y * q.y;
}

double length(CVector p) {
    return sqrt(p * p);
}

CVector unit(CVector p) {
    return 1 / length(p) * p;
}

double project(CVector p, CVector n) {
    return p * unit(n); //点积
}

double operator ^(CVector p, CVector q) {
    return p.x * q.y - q.x * p.y;
}

double area(CVector p, CVector q) {
    return (p ^ q) / 2;
}

double dist(CPoint p, CPoint q) {
    return length(p - q);
}

double dist(CPoint p, CLine l) {
    return fabs((p - l.a) ^ (l.b - l.a))
        / length(l.b - l.a);
}

CPoint rotate(CPoint b, CPoint a,
    double alpha) {//返回点C坐标
    CVector p = b - a;
    return CPoint(a.x + (p.x * cos(alpha)
        - p.y * sin(alpha)),
        a.y + (p.x * sin(alpha)
            + p.y * cos(alpha)));
}

int sideOfLine(CPoint p, CPoint a, CPoint b)
{ //判断p在直线 a->b的哪一侧
    double result = (b - a) ^ (p - a);
    if (IsZero(result))
        return 0; //p 在 a->b上
    else if (result > 0)
        return 1; //p在a->b左侧
    else
        return -1; //p在a->b右侧
}

int n, m, x1, Y1, x2, y2;

const int maxn = 5005;

CPoint polys[maxn][4];
int ans[maxn];

int u, l, ou, ol;
int x, y;

bool PointInPoly(int poly, CPoint p) {
    for (int i = 0; i < 4; i++) {
        CLine l(polys[poly][i], polys[poly][(i + 1) % 4]);
        //if (sideOfLine(p, l.a, l.b) == 0) return true;
        CVector a = polys[poly][i] - p;
        CVector b = polys[poly][(i + 1) % 4] - p;
        if (FLess(a^b, 0)) return false;
    }
    return true;
}

int main() {
    int cas = 0;
    while (cin >> n && n) {
        if (cas != 0) cout << endl;
        cas++;
        cin >> m >> x1 >> Y1 >> x2 >> y2;
        memset(ans, 0, sizeof(ans));
        ou = x1, ol = x1;
        for (int i = 0; i < n; i++) {
            cin >> u >> l;
            polys[i][0] = CPoint(ou, Y1);
            polys[i][1] = CPoint(ol, y2);
            polys[i][2] = CPoint(l, y2);
            polys[i][3] = CPoint(u, Y1);
            ou = u;
            ol = l;
        }
        polys[n][0] = CPoint(ou, Y1);
        polys[n][1] = CPoint(ou, y2);
        polys[n][2] = CPoint(x2, y2);
        polys[n][3] = CPoint(x2, Y1);
        for (int i = 0; i < m; i++) {
            cin >> x >> y;
            CPoint p(x, y);
            int l = 0, r = n + 1;
            while (l < r) {
                int m = (l + r) / 2;
                if (sideOfLine(p, polys[m][2], polys[m][3]) == -1) l = m + 1;
                else r = m;
            }
            ans[l]++;
        }
        for (int i = 0; i < n+1; i++) {
            cout << i << ": " << ans[i] << endl;
        }
    }
}
Space ant

极角排序。

#include <iostream>    
#include <cstring>
#include <string>
#include <queue>   
#include <vector>  
#include <algorithm>   
#include <deque>   

using namespace std;

double PI = acos(-1);
double INF = 1e20;
double EPS = 1e-3;

int Sign(double x) { // 判断 x 是大于0,等于0还是小于0 
    return fabs(x) < EPS ? 0 : x > 0 ? 1 : -1;
}

struct Point {
    double x, y;
    int id;
    Point(double xx = 0, double yy = 0, int id = 0) :x(xx), y(yy), id(id) { }
    Point operator-(const Point & p) const {
        return Point(x - p.x, y - p.y);
    }
    bool operator <(const Point & p) const {
        if (y < p.y)
            return true;
        else if (y > p.y)
            return false;
        else
            return x < p.x;
    }
};

typedef Point Vector;

double Cross(const Vector & v1, const Vector & v2)
{//叉积
    return v1.x * v2.y - v2.x * v1.y;
}

double Distance(const Point & p1, const Point & p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}

struct Comp { //用来定义极角排序规则的函数对象
    Point p0; //以p0为原点进行极角排序,极角相同的,离p0近算小
    Comp(const Point & p) :p0(p.x, p.y) { }
    bool operator ()(const Point & p1, const Point & p2) const {
        int s = Sign(Cross(p1 - p0, p2 - p0));
        if (s > 0)
            return true;
        else if (s < 0)
            return false;
        else {
            if (Distance(p0, p1) < Distance(p0, p2))
                return true;
            else
                return false;
        }
    }
};

const int maxn = 55;
Point ps[maxn];

int T, N;
int x, y, z;

void solve() {
    vector<int> ans;
    sort(ps, ps + N);
    ans.push_back(ps[0].id);
    for (int p = 1; p < N; p++) {
        sort(ps + p, ps + N, Comp(ps[p - 1]));
        ans.push_back(ps[p].id);
    }
    cout << ans.size();
    for (int i = 0; i < ans.size(); i++) cout << " " << ans[i];
    cout << endl;
}

int main() {
    cin >> T;
    while (T--) {
        cin >> N;
        for (int i = 0; i < N; i++) {
            cin >> z >> x >> y;
            ps[i] = Point(x, y, z);
        }
        solve();
    }
}
Line of Sight

区间合并很有趣。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
using namespace std;

const double EPS=1e-8;
const int MAXN=200;

int dblcmp(double x){
    return fabs(x)<EPS?0:(x>0?1:-1);
}

struct Point;
typedef Point Vector;

struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y):x(_x),y(_y){}
    Vector operator -(Point p){
        return Vector(x-p.x,y-p.y);
    }
    double operator ^(Vector v){ //叉积
        return x*v.y-y*v.x;
    }
};

struct Region{ //遮挡区域
    double lx,rx;
    Region(){}
    Region(double _lx,double _rx):lx(_lx),rx(_rx){}
};

struct Line{
    Point p1,p2;
    Line(){}
    Line(Point _p1,Point _p2):p1(_p1),p2(_p2){}
    bool input(){
        double x1,x2,y;
        cin>>x1>>x2>>y;
        if(x1==0&&x2==0&&y==0) return false;
        p1=Point(x1,y); p2=Point(x2,y);
        return true;
    }
    double intersectionPointX(Line l){ //定点分比法求交点(x坐标)
        double s1=(l.p1-p1)^(p2-p1);
        double s2=(l.p2-p1)^(p2-p1);
        return (s2*l.p1.x-s1*l.p2.x)/(s2-s1);
    }
    double length(){
        return p2.x-p1.x;
    }
};


Line house,property;
vector<Line> obstacles;
vector<Region> regions;

bool compare(const Region& r1,const Region& r2){
    return r1.lx<r2.lx;
}

void solve(){
    int m=obstacles.size();
    if(!m){
        cout<<fixed<<setprecision(2)<<property.length()<<endl;
        return ;
    }
    regions.clear();
    for(int i=0;i<m;++i){ //求每个障碍线的遮挡区域
        Point left=obstacles[i].p1;
        Point right=obstacles[i].p2;
        double x1=property.intersectionPointX(Line(left,house.p2)); //左端点
        double x2=property.intersectionPointX(Line(right,house.p1)); //右端点
        regions.push_back(Region(max(property.p1.x,x1),min(property.p2.x,x2)));
    }
    sort(regions.begin(),regions.end(),compare); //排序,方便后面合并相连的遮挡区域
    vector<Region> r;
    Region region=Region(regions[0].lx,regions[0].rx);
    for(int i=1;i<m;++i){ //合并相连的遮挡区域
        if(region.rx>regions[i].lx-EPS)
            region.rx=max(region.rx,regions[i].rx);
        else{
            if(region.rx>region.lx) //一开始没有判断这个,wa了好久。。
                r.push_back(region);
            region=Region(regions[i].lx,regions[i].rx);
        }
    }
    if(region.rx>region.lx)
        r.push_back(region);
    m=r.size();
    double ans=r[0].lx-property.p1.x;
    for(int i=0;i<m-1;++i){
        ans=max(ans,r[i+1].lx-r[i].rx);
    }
    ans=max(ans,property.p2.x-r[m-1].rx);
    if(ans<EPS) cout<<"No View"<<endl;
    else cout<<fixed<<setprecision(2)<<ans<<endl;
}

int main(){
    while(house.input()){
        property.input();
        int n;
        cin>>n;
        Line obstacle;
        obstacles.clear();
        for(int i=0;i<n;++i){
            obstacle.input();
            if(obstacle.p1.y>house.p1.y-EPS||obstacle.p1.y<property.p1.y+EPS)
                continue; //排除不在房屋和观光线之间的
            obstacles.push_back(obstacle);
        }
        solve();
    }
    return 0;
}
The Fortified Forest

凸包+状压。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;

const int maxn = 16;
int N;

struct tree {
    int x, y, v, l;
    tree() {}
    tree(int x, int y, int v, int l) :x(x), y(y), v(v), l(l) {}
} f[maxn];

#define EPS 1e-3
#define inf 0x3f3f3f3f

int Sign(double x) { // 判断 x 是大于0,等于0还是小于0 
    return fabs(x) < EPS ? 0 : x > 0 ? 1 : -1;
}

struct Point {
    double x, y;
    Point(double xx = 0, double yy = 0) :x(xx), y(yy) { }
    Point operator-(const Point & p) const {
        return Point(x - p.x, y - p.y);
    }
    bool operator <(const Point & p) const {
        if (y < p.y)
            return true;
        else if (y > p.y)
            return false;
        else
            return x < p.x;
    }
};

typedef Point Vector;

double Cross(const Vector & v1, const Vector & v2)
{//叉积
    return v1.x * v2.y - v2.x * v1.y;
}

double Distance(const Point & p1, const Point & p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}

struct Comp { //用来定义极角排序规则的函数对象
    Point p0; //以p0为原点进行极角排序,极角相同的,离p0近算小
    Comp(const Point & p) :p0(p.x, p.y) { }
    bool operator ()(const Point & p1, const Point & p2) const {
        int s = Sign(Cross(p1 - p0, p2 - p0));
        if (s > 0)
            return true;
        else if (s < 0)
            return false;
        else {
            if (Distance(p0, p1) < Distance(p0, p2))
                return true;
            else
                return false;
        }
    }
};

// return wood needed
double Graham(vector<Point> & points, vector<Point> & stack) {
    //points是点集合
    if (points.size() == 1) return 0;
    if (points.size() == 2) return Distance(points[0], points[1]) * 2;
    stack.clear();
    //先按坐标排序,最左下的放到points[0] 
    sort(points.begin(), points.end());
    //以points[0] 为原点进行极角排序 
    sort(points.begin() + 1, points.end(), Comp(points[0]));
    stack.push_back(points[0]);
    stack.push_back(points[1]);
    stack.push_back(points[2]);
    for (int i = 3; i < points.size(); ++i) {
        while (true) {
            Point p2 = *(stack.end() - 1);
            Point p1 = *(stack.end() - 2);
            if (Sign(Cross(p2 - p1, points[i] - p2) <= 0))
                //p2->points[i]没有向左转,就让p2出栈 
                stack.pop_back();
            else
                break;
        }
        stack.push_back(points[i]);
    }
    double res = 0;
    for (int i = 0; i < stack.size(); i++) {
        res += Distance(stack[i], stack[(i + 1) % stack.size()]);
    }
    return res;
}

int x, y, v, l;
int main() {
    int cas = 0;
    while (cin >> N && N) {
        if (cas) cout << endl;
        cas++;

        for (int i = 0; i < N; i++) {
            cin >> x >> y >> v >> l;
            f[i] = tree(x, y, v, l);
        }

        int mnv = inf;
        double exw = 0;
        vector<int> mncuts;

        int mx_st = (1 << N) - 1;
        for (int st = 1; st < mx_st; st++) {
            vector<Point> poly;
            vector<int> cuts;
            int tv = 0, tl = 0;
            for (int i = 0; i < N; i++) {
                if (st&(1 << i)) {
                    tv += f[i].v;
                    tl += f[i].l;
                    cuts.push_back(i);
                }
                else {
                    poly.push_back(Point(f[i].x, f[i].y));
                }
            }
            vector<Point> hull;
            double s = Graham(poly, hull);
            if (tl > s && tv < mnv) {
                mnv = tv;
                exw = tl - s;
                mncuts = cuts;
            }
        }
        cout << "Forest " << cas << endl;
        cout << "Cut these trees:";
        for (int i = 0; i < mncuts.size(); i++) cout << " " << mncuts[i] + 1;
        cout << endl;
        cout << "Extra wood: " << fixed << setprecision(2) << exw << endl;
    }
}

Suffix Array

Substrings

多字串最长公共子串背板。

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <string>

using namespace std;

const int maxn = 10005;
int N;
int wa[maxn], wb[maxn], wc[maxn], wd[maxn];
int sa[maxn];

// n: strlen(s), m: 128(ASCII unique chars)
void buildSA(int* s, int n, int* sa, int m = 255) {
    int i, j, p, *pm = wa, *k2sa = wb, *t;
    // k1 radix sort
    for (i = 0; i < m; i++) wd[i] = 0;
    for (i = 0; i < n; i++) wd[pm[i] = s[i]]++;
    for (i = 1; i < m; i++) wd[i] += wd[i - 1];
    for (i = n - 1; i >= 0; i--) sa[--wd[pm[i]]] = i;
    // loops j->2j
    for (j = p = 1; p < n; j <<= 1, m = p) {
        // generate k2sa
        for (p = 0, i = n - j; i < n; i++) k2sa[p++] = i; // null k2
        for (i = 0; i < n; i++) if (sa[i] >= j) k2sa[p++] = sa[i] - j;
        // k2 radix sort
        for (i = 0; i < m; i++) wd[i] = 0;
        for (i = 0; i < n; i++) wd[wc[i] = pm[k2sa[i]]]++;
        for (i = 1; i < m; i++) wd[i] += wd[i - 1];
        for (i = n - 1; i >= 0; i--) sa[--wd[wc[i]]] = k2sa[i];
        // update pm
        for (t = pm, pm = k2sa, k2sa = t, pm[sa[0]] = 0, p = i = 1; i < n; i++) {
            int a = sa[i - 1], b = sa[i];
            if (k2sa[a] == k2sa[b] && k2sa[a + j] == k2sa[b + j])
                pm[sa[i]] = p - 1;
            else pm[sa[i]] = p++;
        }
    }
}

int Rank[maxn], height[maxn];
void buildHeight(int* str, int n) {
    int i, j, k;
    for (i = 0; i < n; i++) Rank[sa[i]] = i;
    for (i = k = 0; i < n; height[Rank[i++]] = k)
        for (k ? k-- : 0, j = sa[Rank[i] - 1];
            str[i + k] == str[j + k];
            k++);
}


int s[maxn], id[maxn];
int vis[105];

int T, M;
string a;

bool check(int mid) {
    memset(vis, 0, sizeof(vis));
    int cnt = 0;
    for (int i = 1; i <= N; i++) {
        if (height[i] >= mid) {
            for (int j = 1; j <= M; j++) {
                if (id[sa[i]] == j) {
                    if (!vis[j]) cnt++;
                    vis[j] = 1;
                }
                if (id[sa[i-1]] == j) {
                    if (!vis[j]) cnt++;
                    vis[j] = 1;
                }
            }
        }
        else {
            if (cnt >= M) return true;
            cnt = 0;
            memset(vis, 0, sizeof(vis));
        }
    }
    if (cnt >= M) return true;
    return false;
}

int main() {
    cin >> T;
    while (T--) {
        int l = 0, offset = 1;
        cin >> M;
        for (int i = 1; i <= M; i++) {
            cin >> a;
            for (int j = 0; j < a.size(); j++) id[l] = i, s[l++] = a[j];
            s[l++] = '#' + offset++;
            for (int j = a.size() - 1; j >= 0; j--) id[l] = i, s[l++] = a[j];
            s[l++] = '#' + offset++;
        }
        N = l;
        buildSA(s, N, sa);
        buildHeight(s, N);
        int left = 0, right = N;
        while (left < right) {
            int mid = (left + right) / 2;
            if (check(mid)) left = mid + 1;
            else right = mid;
        }
        cout << left - 1 << endl;
    }
}