• [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
    ", i, j);
                }
            }
            printf("
    ");
        }
        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
    ") : printf("No
    ");
        }
        return 0;
    }
    

    D. Hack Portals

    题意

    题解

    代码

    E. Half-consecutive Numbers

    题意

    给定一个$N$,求最小的$rgeq 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$。
    由于$nleq10{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
    ", i * i - 1);
            if (isSquare((i * i + 1) / 2)) printf("%lld
    ", 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
    ", 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
    ", res);
        }
        return 0;
    }
    

    G. Query on a string

    题意

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

    1. 操作$Cspace ispace ch$:将$S$的第$i$个字符改成$ch$;
    2. 查询$Qspace ispace 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
    ");
                    else printf("%d
    ", 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("
    ");
        }
        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
    ", 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=inom{n}{3}-frac{1}{2}sum^{n}_{i=1}{d_i imes (n-1-d_i)}$个。
    要让它最小,根据均值不等式我们容易得到:当$d_i=frac{n-1}{2}$时取最小值$inom{n}{3}-frac{1}{2} imes n imes frac{n-1}{2} imes (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
    ", 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 ? '
    ' : ' ');
                }
            }
        }
        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
    ", mcmf.minCost());
        }
        return 0;
    }
    
    
  • 相关阅读:
    android5.0 BLE 蓝牙4.0+浅析demo搜索(一)
    android4.3 Bluetooth(le)分析之startLeScan分析
    android4.3 Bluetooth分析之扫描分析
    JAVA 如何将String进行大小写转换
    用Java将字符串的首字母转换大小写
    关于Android中设置闹钟的相对比较完善的解决方案
    Android闹钟 AlarmManager的使用
    关于Android中设置闹钟的相对完善的解决方案
    android闹钟实现原理
    Android利用AlarmManager执行定时任务
  • 原文地址:https://www.cnblogs.com/jstztzy/p/7517920.html
Copyright © 2020-2023  润新知