[Contest]2017 ACM/ICPC Asia Regional Urumqi Online(B D待补)

A. Banana

题意

给定$N$个猴子对香蕉喜欢的关系,和$M$个香蕉产自哪个地区的关系。输出所有猴子和地区的关系。

题解

暴力。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 59;
bool a[N][N], b[N][N], c[N][N];

inline int read() {
    int s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

int main() {
    int T = read();
    while (T--) {
        int n = read(), m = read();
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= n; i++) {
            int x = read(), y = read();
            a[x][y] = 1;
        }
        memset(b, 0, sizeof(b));
        for (int i = 1; i <= m; i++) {
            int x = read(), y = read();
            b[x][y] = 1;
        }
        memset(c, 0, sizeof(c));
        for (int i = 1; i < N; i++) {
            for (int j = 1; j < N; j++) {
                for (int k = 1; k < N; k++) {
                    if (a[i][k] && b[k][j]) c[i][j] = 1;
                }
            }
        }
        for (int i = 1; i < N; i++) {
            for (int j = 1; j < N; j++) {
                if (c[i][j]) printf("%d %d\n", i, j);
            }
        }
        printf("\n");
    }
    return 0;
}

B. Out-of-control cars

题意

题解

代码

C. Coconut

题意

一个人从$1$城依次到$N$城,从$i$城到$i+1$城需要$D_i$天,每天要喝$b$瓶饮料,到达$i$城后又可以获得$C_i$瓶饮料。判断这个人能否每天都喝饮料。

题解

模拟。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1009;

int c[N], d[N];

inline int read() {
    int s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

int main() {
    int t = read();
    while (t--) {
        int n = read(), b = read();
        for (int i = 1; i <= n; i++) c[i] = read();
        for (int i = 1; i < n; i++) d[i] = read();
        ll cur = 0;
        bool flag = true;
        for (int i = 1; i < n; i++) {
            cur += c[i];
            cur -= d[i] * b;
            if (cur < 0) {
                flag = false;
                break;
            }
        }
        flag ? printf("Yes\n") : printf("No\n");
    }
    return 0;
}

D. Hack Portals

题意

题解

代码

E. Half-consecutive Numbers

题意

给定一个$N$,求最小的$r\geq N$使得$t_r=\frac{1}{2}r(r+1)$是一个平方数。

题解

考虑$\frac{1}{2}r(r+1)$是个完全平方数,要么$r=a2,r+1=2b2$,要么$r=2a2,r+1=b2$。
由于$n\leq10{16}$,故只需要枚举$108$以内的$a$即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll r[25] = {
    0ll,
    1ll,
    8ll,
    49ll,
    288ll,
    1681ll,
    9800ll,
    57121ll,
    332928ll,
    1940449ll,
    11309768ll,
    65918161ll,
    384199200ll,
    2239277041ll,
    13051463048ll,
    76069501249ll,
    443365544448ll,
    2584123765441ll,
    15061377048200ll,
    87784138523761ll,
    511643454094368ll,
    2982076586042449ll,
    17380816062160328ll,
};

inline ll read() {
    ll s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

int main() {
    /*
    for (ll i = 1; i <= 1e8; i += 2) {
        if (isSquare((i * i - 1) / 2)) printf("%lld\n", i * i - 1);
        if (isSquare((i * i + 1) / 2)) printf("%lld\n", i * i);
    }
    */
    ll T = read();
    for (ll t = 1; t <= T; t++) {
        ll n = read(), i = 0;
        for (; r[i] < n; i++);
        printf("Case #%lld: %lld\n", t, r[i]);
    }
}

F. Islands

题意

给定一个$N$个点$M$条边的有向图,求最少添加多少条边,使得新图变成强连通图。

题解

首先找出强连通分量,然后把每个强连通分量缩成一个点,这样就得到一个$DAG$。
然后设有$a$个节点的入度为$0$,$b$个节点的出度为$0$,则$res=max(a,b)$,因为只要把其中一边连成环即可。
注意特殊情况:当原图已经强连通时,答案是$0$而不是$1$!

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5+9;
vector<int> g[N];
stack<int> s;
int in0[N], ou0[N];
int pre[N], low[N], scc[N], dfsClock, sccCnt;

inline int read() {
    int s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

inline void dfs(int u) {
    pre[u] = low[u] = ++dfsClock;
    s.push(u);
    for (auto v : g[u]) {
        if (!pre[v]) {
            dfs(v);
            low[u] = min(low[u], low[v]);
        }
        else
            if (!scc[v]) low[u] = min(low[u], pre[v]);
    }
    if (low[u] == pre[u]) {
        sccCnt++;
        for (;;) {
            int x = s.top(); s.pop();
            scc[x] = sccCnt;
            if (x == u) break;
        }
    }
}

inline void findScc(int n) {
    dfsClock = sccCnt = 0;
    memset(scc, 0, sizeof(scc));
    memset(low, 0, sizeof(low));
    memset(pre, 0, sizeof(pre));
    for (int i = 1; i <= n; i++) if (!pre[i]) dfs(i);
}

int main() {
    int T = read();
    while (T--) {
        int n = read(), m = read();
        for (int i = 1; i <= n; i++) g[i].clear();
        for (int i = 1; i <= m; i++) {
            int u = read(), v = read();
            g[u].push_back(v);
        }
        findScc(n);
        for (int i = 1; i <= sccCnt; i++) in0[i] = ou0[i] = 1;
        for (int u = 1; u <= n; u++) {
            for (auto v : g[u]) {
                if (scc[u] != scc[v]) in0[ scc[v] ] = ou0[ scc[u] ] = 0;
            }
        }
        int a = 0, b = 0;
        for (int i = 1; i <= sccCnt; i++) {
            if (in0[i]) a++;
            if (ou0[i]) b++;
        }
        int res = sccCnt == 1 ? 0 : max(a, b);
        printf("%d\n", res);
    }
    return 0;
}

G. Query on a string

题意

给定两个字符串$S$和$T(|T|\leq 10)$,要求在$S$上维护:

  1. 操作$C\space i\space ch$:将$S$的第$i$个字符改成$ch$;
  2. 查询$Q\space i\space j$:返回$S$中第$i$到第$j$位$T$出现的次数。

题解

首先预处理出$S$中每一位开始连续$|T|$位能否和$T$匹配。
对于查询直接输出前缀和即可;
对于修改我们用树状数组维护预处理的结果,由于$|T|\leq 10$,修改一位最多影响十位的匹配结果,暴力修改即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5+9;
char s[N], t[11];
int slen, tlen, bit[2 * N];
bool vis[N];

inline int lowbit(int x) {
    return x & (-x);
}
inline void add(int x, int y) {
    while (x < N) {
        bit[x] += y;
        x += lowbit(x);
    }
}
inline int preSum(int x) {
    int ret = 0;
    while (x > 0) {
        ret += bit[x];
        x -= lowbit(x);
    }
    return ret;
}
inline int segSum(int l, int r) {
    return preSum(r) - preSum(l - 1);
}

inline int read() {
    int s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

int main() {
    int T = read();
    while (T--) {
        int n = read();
        scanf("%s", s + 1), slen = strlen(s + 1);
        scanf("%s", t + 1), tlen = strlen(t + 1);
        memset(bit, 0, sizeof(bit));
        memset(vis, 0, sizeof(vis));
        for (int i = 1; i + tlen - 1 <= slen; i++) {
            bool flag = 1;
            for (int j = 1; j <= tlen; j++) {
                if (s[i + j - 1] != t[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) add(i, 1), vis[i] = 1;
        }
        while (n--) {
            char q[5]; scanf("%s", q);
            if (q[0] == 'Q') {
                int x = read(), y = read();
                if (y - tlen + 1 < x) printf("0\n");
                else printf("%d\n", segSum(x, y - tlen + 1));
            }
            if (q[0] == 'C') {
                int p = read(); char c[5]; scanf("%s", c);
                s[p] = c[0];
                for (int i = max(1, p - tlen + 1); i <= min(slen - tlen + 1, p); i++) {
                    bool flag = 1;
                    for (int j = 1; j <= tlen; j++) {
                        if (s[i + j - 1] != t[j]) {
                            flag = 0;
                            break;
                        }
                    }
                    if (flag != vis[i]) {
                        if (vis[i]) add(i, -1);
                        else add(i, 1);
                        vis[i] = !vis[i];
                    }
                }
            }
        }
        printf("\n");
    }
    return 0;
}

H. Skiing

题意

求$DAG$上的最长路径。

题解

直接跑$SPFA$或者记忆化搜索即可。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e4+9;
const int INF = 0x3f3f3f3f;
int n, m, dist[N];
bool vis[N];
vector<pair<int, int> > g[N];

inline int read() {
    int s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

inline void SPFA() {
    queue<int> q;
    memset(vis, 0, sizeof(vis));
    memset(dist, -INF, sizeof(dist));
    q.push(0), vis[0] = 1, dist[0] = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop(), vis[u] = 0;
        for (auto e : g[u]) {
            int v = e.first, w = e.second;
            if (dist[u] + w > dist[v]) {
                dist[v] = dist[u] + w;
                if (!vis[v]) q.push(v), vis[v] = 1;
            }
        }
    }
    printf("%d\n", dist[n + 1]);
}

int main() {
    int t = read();
    while (t--) {
        n = read(), m = read();
        for (int i = 1; i <= n; i++) g[i].clear();
        for (int i = 1; i <= m; i++) {
            int s = read(), t = read(), l = read();
            g[s].push_back( make_pair(t, l) );
        }
        for (int i = 1; i <= n; i++) {
            g[0].push_back( make_pair(i, 0) );
            g[i].push_back( make_pair(n + 1, 0) );
        }
        SPFA();
    }
    return 0;
}

I. Colored Graph

题意

求一种给$n$阶完全图的边$01$染色的方案,使得相同颜色的三元环最少,并求出这个最少数量。

题解

我们考虑任意一个含有不同颜色的三元环,一定是两个顶点的两条边颜色不同。
记$d_i$为与顶点$i$相连染$1$的边的数量,则相同颜色的三元环有$res=\binom{n}{3}-\frac{1}{2}\sum^{n}_{i=1}{d_i\times (n-1-d_i)}$个。
要让它最小,根据均值不等式我们容易得到:当$d_i=\frac{n-1}{2}$时取最小值$\binom{n}{3}-\frac{1}{2}\times n\times \frac{n-1}{2}\times (n-1-\frac{n-1}{2})$。
输出方案时,反正是要每个顶点连$\frac{n-1}{2}$条颜色为$1$的边,直接贪心地建图即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;

const int N = 509;
int g[N][N];
pii v[N];

inline int read() {
    int s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

int main() {
    int T = read();
    while (T--) {
        int n = read();
        int res = n * (n - 1) * (n - 2) / 6 - n * ((n - 1) / 2 * (n - 1 - (n - 1) / 2)) / 2;
        for (int i = 1; i <= n; i++) {
            v[i].first = (n - 1) / 2;
            v[i].second = i;
        }
        memset(g, 0, sizeof(g));
        for (int i = 1; i <= n; i++) {
            sort(v + i, v + n + 1);
            for (int j = n; j > max(i, n - v[i].first); j--) {
                g[ v[i].second ][ v[j].second ] = g[ v[j].second ][ v[i].second ] = 1;
                v[j].first--;
            }
        }
        printf("%d\n", res);
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                printf("%d%c", i == j ? 0 : g[i][j] + 1, j == n ? '\n' : ' ');
            }
        }
    }
    return 0;
}

J. Our Journey of Dalian Ends

题意

给定一个无向图,不得重复经过同一顶点,求顶点$A$经过顶点$C$达到顶点$B$的最短路径。

题解

我们先把超级源连$A$和$B$,超级汇连$C$。
然后每个顶点拆成一个入点、一个出点,之间连一条容量为$1$、费用为$0$的边(注意:顶点$C$拆成的边容量为$2$)。
最后直接跑最小费用最大流。若到超级汇的流量不为$2$,则不存在这样的路径,否则输出最小费用即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll N = 2e4;
const ll M = 2e5+9;
const ll INF = 0x3f3f3f3f;
const string s1 = "Dalian";
const string s2 = "Xian";
const string s3 = "Shanghai";
ll n, m;
map<string, ll> hsh;

inline ll read() {
    ll s = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return s * x;
}

struct MCMF {
    struct Edge {
        ll fr, to, cap, flw, cst, nxt;
        Edge() {}
        Edge(ll fr, ll to, ll cap, ll flw, ll cst, ll nxt) {
            this->fr = fr; this->to = to; this->cap = cap; this->flw = flw; this->cst = cst; this->nxt = nxt;
        }
    } e[M];

    ll n, m, s, t, tot;
    ll hed[M], dst[M], vis[M], pre[M], cag[M];
    queue<ll> q;

    void init() {
        tot = 0;
        for (ll i = s; i <= t; i++) hed[i] = -1;
    }
    void add(ll x, ll y, ll v, ll c) {
        e[tot] = Edge(x, y, v, 0, c, hed[x]); hed[x] = tot++;
        e[tot] = Edge(y, x, 0, 0, -c, hed[y]); hed[y] = tot++;
    }
    bool SPFA(ll& flow, ll& cost) {
        for (ll i = s; i <= t; i++) dst[i] = INF, vis[i] = 0;
        while (!q.empty()) q.pop();
        q.push(s); dst[s] = 0; vis[s] = 1; pre[s] = 0; cag[s] = INF;
        while (!q.empty()) {
            ll u = q.front(); q.pop(); vis[u] = 0;
            for (ll i = hed[u]; ~i; i = e[i].nxt) {
                Edge& edge = e[i];
                if (edge.cap > edge.flw && dst[edge.to] > dst[u] + edge.cst) {
                    dst[edge.to] = dst[u] + edge.cst;
                    pre[edge.to] = i;
                    cag[edge.to] = min(cag[u], edge.cap - edge.flw);
                    if (!vis[edge.to]) q.push(edge.to), vis[edge.to] = 1;
                }
            }
        }
        if (dst[t] == INF) return 0;
        flow += cag[t];
        cost += dst[t] * cag[t];
        ll u = t;
        while (u != s) {
            e[ pre[u] ].flw += cag[t];
            e[ pre[u] ^ 1 ].flw -= cag[t];
            u = e[ pre[u] ].fr;
        }
        return 1;
    }
    ll minCost() {
        ll flow = 0, cost = 0;
        while (SPFA(flow, cost));
        return flow != 2 ? -1 : cost;
    }
} mcmf;

int main() {
    ll T = read();
    while (T--) {
        n = 0, m = read(); hsh.clear();
        mcmf.n = 2 * N + 2; mcmf.s = 0; mcmf.t = 2 * N + 1; mcmf.init();
        for (ll i = 1; i <= m; i++) {
            string u, v; cin >> u >> v; 
            ll c = read();
            if (hsh[u] == 0) {
                hsh[u] = ++n;
                if (u != s3) mcmf.add(hsh[u], hsh[u] + N, 1, 0);
            }
            if (hsh[v] == 0) {
                hsh[v] = ++n;
                if (v != s3) mcmf.add(hsh[v], hsh[v] + N, 1, 0);
            }
            if (u == s3) mcmf.add(hsh[u], hsh[v], 1, c);
            else mcmf.add(hsh[u] + N, hsh[v], 1, c);
            if (v == s3) mcmf.add(hsh[v], hsh[u], 1, c);
            else mcmf.add(hsh[v] + N, hsh[u], 1, c);
        }
        mcmf.add(mcmf.s, hsh[s3], 2, 0);
        mcmf.add(hsh[s2] + N, mcmf.t, 1, 0);
        mcmf.add(hsh[s1] + N, mcmf.t, 1, 0);
        printf("%lld\n", mcmf.minCost());
    }
    return 0;
}

posted @ 2017-09-13 21:55  jstztzy  阅读(166)  评论(0编辑  收藏  举报