zoukankan      html  css  js  c++  java
  • The Preliminary Contest for ICPC Asia Xuzhou 2019

    A What is better?

    推不出来,写个程序打表,用扩展中国剩余定理合并,居然会溢出longlong,还好不会溢出__int128(赛后exit(-1)测试),实际证明溢出返回-1是不靠谱的,毕竟后面可以又把它搞小了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef __int128 lll;
    
    const int MAXK = 10 + 5;
    
    void exgcd(lll a, lll b, lll &x, lll &y) {
        if(!b)
            x = 1, y = 0;
        else
            exgcd(b, a % b, y, x), y -= a / b * x;
    }
    
    lll inv(ll a, ll b) {
        lll x = 0, y = 0;
        exgcd(a, b, x, y);
        x = (x % b + b) % b;
        if(!x)
            x += b;
        return x;
    }
    
    int k;
    lll c[MAXK], m[MAXK];
    
    lll exCRT(int k) {
        lll c1, c2, m1, m2, t;
        for(int i = 2; i <= k; ++i) {
            m1 = m[i - 1], m2 = m[i], c1 = c[i - 1], c2 = c[i];
            t = __gcd(m1, m2);
            if((c2 - c1) % t != 0)
                return -1;
            m[i] = m1 / t * m2;
            if(m[i] <= 0)
                exit(-1);
            c[i] = inv(m1 / t, m2 / t) * ((c2 - c1) / t) % (m2 / t) * m1 + c1;
            c[i] = (c[i] % m[i] + m[i]) % m[i];
        }
        return c[k];
    }
    
    /*map<pair<int, int>, pair<bool, int> > M;
    
    bool dfs(int id, int pre) {
        if(M.count({id, pre}))
            return M[ {id, pre}].first;
        if(pre == -1) {
            for(int i = 1; i < id; ++i) {
                if(dfs(id - i, i) == false) {
                    M[{id, pre}] = {true, i};
                    return true;
                }
            }
            M[{id, pre}] = {false, -1};
            return false;
        } else {
            int c = min(2 * pre, id);
            if(c == id) {
                M[{id, pre}] = {true, c};
                return true;
            }
    
            for(int i = 1; i <= c; ++i) {
                if(dfs(id - i, i) == false) {
                    M[{id, pre}] = {true, i};);
                    return true;
                }
            }
            M[{id, pre}] = {false, -1};
            return false;
        }
    }*/
    
    ll f[72 + 5];
    
    int main() {
    #ifdef local
        freopen("lyz.in", "r", stdin);
    #endif // local
        /*for(int i = 2; i <= 100; ++i) {
            printf("i=%d", i);
            if(dfs(i, -1)) {
                printf(" WIN
    ");
                printf(" TO TAKE %d
    ", M[ {i, -1}].second);
            } else
                printf(" FAIL
    ");
        }
    
        for(int j = 1; j <= 20; ++j) {
            for(int k = -1; k <= 20; ++k) {
                if(M.count({j, k})) {
                    printf("(%d,%d) 
    ", j, k);
                    if(M[ {j, k}].first == true) {
                        printf(" WIN
    ");
                        printf(" TO TAKE %d
    ", M[ {j, k}].second);
                    } else {
                        printf(" FAIL
    ");
                    }
                    puts("");
                }
            }
        }*/
    
        int k;
        scanf("%d", &k);
        bool suc = 1;
        for(int i = 1; i <= k; ++i) {
            ll tmp1, tmp2;
            scanf("%lld%lld", &tmp1, &tmp2);
            m[i] = tmp1;
            c[i] = tmp2;
            if(c[i] > 1e15) {
                suc = false;
            }
        }
    
        if(!suc) {
            puts("Tankernb!");
            return 0;
        }
    
        lll n = exCRT(k);
        if(n <= 1 || n > 1e15) {
            puts("Tankernb!");
            return 0;
        }
        f[1] = 2;
        f[2] = 3;
        for(int i = 3; i <= 72; ++i) {
            f[i] = f[i - 1] + f[i - 2];
            if(f[i] >= 1e15) {
                //cout<<"i="<<i<<endl;
                break;
            }
        }
        for(int i = 1; i <= 72; ++i) {
            if(n == f[i]) {
                puts("Lbnb!");
                return 0;
            }
        }
        puts("Zgxnb!");
        return 0;
    }
    

    B so easy

    一开始1e6弄个set莽了两次,果断T了,事实证明平衡树的常数的确相比离散化是在是太大了。用个并查集维护,删除一个节点的时候,假如他没有被删除过,那么就把他指向他的下一个元素(无论他的下一个元素是不是被删了都可以),并且把这个元素设置为“删除”,下面参照非递归路径压缩并查集弄了一个非递归路径压缩,实测727ms还算可以。

    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read() {
        int x = 0;
        char ch = getchar();
        while(ch < '0' || ch > '9')
            ch = getchar();
        do {
            x = (x << 3) + (x << 1) + ch - '0';
            ch = getchar();
        } while(ch >= '0' && ch <= '9');
        return x;
    }
    
    const int MAXN = 1e6;
    int z[MAXN + 5], x[MAXN + 5];
    int px[2 * MAXN + 5], xtop;
    
    int nxt[2 * MAXN + 5];
    bool vis[2 * MAXN + 5] = {};
    
    inline int find(int i) {
        int cur = nxt[i];
        while(vis[cur]) {
            cur = nxt[cur];
        }
        while(nxt[i] != cur) {
            int t = nxt[i];
            nxt[i] = cur;
            i = t;
        }
        return cur;
    }
    
    int main() {
    #ifdef local
        freopen("lyz.in", "r", stdin);
    #endif // local
        int n = read(), q = read();
        xtop = 0;
        for(int i = 1; i <= q; ++i) {
            z[i] = read(), x[i] = read();
            px[++xtop] = x[i];
            if(z[i] == 1)
                px[++xtop] = x[i] + 1;
        }
        sort(px + 1, px + 1 + xtop);
        xtop = unique(px + 1, px + 1 + xtop) - (px + 1);
        for(int i = 1; i <= q; ++i)
            x[i] = lower_bound(px + 1, px + 1 + xtop, x[i]) - (px);
    
        for(int i = 1; i <= xtop; ++i)
            nxt[i] = i;
    
        for(int i = 1; i <= q; ++i) {
            if(z[i] == 1) {
                if(!vis[x[i]]) {
                    vis[x[i]] = true;
                    nxt[x[i]] = nxt[x[i] + 1];
                    find(x[i]);
                }
            } else {
                int res = find(x[i]);
                printf("%d
    ", px[res]);
            }
        }
    
    }
    

    J Random Access Iterator

    一个逗逼签到题,根据期望的线性性蛮好推的,首先第一遍dfs算出最大深度和各个节点的深度(虽然各个节点的深度是不必要的),第二遍dfs把dp数组算出来。设dp[i]表示i的子树给出最大深度的概率。那么对于深度为最大深度的叶子节点,dp[i]=1,其他叶子dp[i]=0。那么对于中间节点,它的所有k个子节点能提供最大深度的概率的期望就是各个子节点的dp值的平均值。它不能给出正确深度的概率就是这个期望的补数连续乘k次。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MOD = 1e9 + 7;
    
    const int MAXN = 1e6;
    vector<int> G[MAXN + 5];
    
    int qpow(ll x, int n) {
        ll res = 1;
        while(n) {
            if(n & 1)
                res = res * x % MOD;
            x = x * x % MOD;
            n >>= 1;
        }
        return res;
    }
    
    int dp[MAXN + 5];
    
    int MAXD;
    
    void dfs1(int u, int p, int d) {
        MAXD = max(MAXD, d);
        for(auto v : G[u]) {
            if(v != p) {
                dfs1(v, u, d + 1);
            }
        }
        return;
    }
    
    void dfs2(int u, int p, int d) {
        if(d == MAXD) {
            dp[u] = 1;
            return;
        }
        ll P = 0;
        int n = 0;
        for(auto v : G[u]) {
            if(v != p) {
                dfs2(v, u, d + 1);
                P += dp[v];
                ++n;
            }
        }
        P = P * qpow(n, MOD - 2) % MOD;
        ll Q = (1ll - P + MOD) % MOD;
        Q = qpow(Q, n);
        dp[u] = (1ll - Q + MOD) % MOD;
        return;
    }
    
    int main() {
    #ifdef local
        freopen("lyz.in", "r", stdin);
    #endif // local
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n - 1; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
    
        dfs1(1, -1, 1);
        dfs2(1, -1, 1);
    
        printf("%d
    ", dp[1]);
    }
    

    M Longest subsequence

    设dp[i]表示匹配t串的长度为i的前缀需要用到s的最短长度,特别地为了统一,dp[0]=0,INF表示无法匹配。设pos[i][ch]表示在s串的i位置及其以后第一个ch出现的下标。

    那么只有两种情况,第一,匹配了长度为i的前缀,然后从第i+1个字符开始严格大,i从0开始,这样就暴力一遍比t[i+1]大的最近的pos就行了。第二,完全匹配t,然后后面有多少加多少,注意至少要加一个

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int INF = 1e9;
    const int MAXN = 1e6;
    char s[MAXN + 5], t[MAXN + 5];
    int dp[MAXN + 5];
    
    int pos[MAXN + 5][26];
    
    int main() {
    #ifdef local
        freopen("lyz.in", "r", stdin);
    #endif // local
        int n, m;
        while(~scanf("%d%d", &n, &m)) {
            scanf("%s%s", s + 1, t + 1);
            dp[0] = 0;
            for(int i = 1; i <= m; ++i)
                dp[i] = INF;
            for(int i = 1; i <= m; ++i) {
                for(int j = dp[i - 1] + 1; j <= n; ++j) {
                    if(s[j] == t[i]) {
                        dp[i] = j;
                        break;
                    }
                }
                if(dp[i] == INF)
                    break;
            }
    
            for(int i = 0; i < 26; ++i)
                pos[n + 1][i] = INF;
            for(int i = n; i >= 1; --i) {
                for(int j = 0; j < 26; ++j)
                    pos[i][j] = pos[i + 1][j];
                pos[i][s[i] - 'a'] = i;
            }
    
            int ans = -1;
    
            for(int i = 0; i <= m; ++i) {
                int last = INF;
                if(dp[i] == INF)
                    break;
                else {
                    if(i == m) {
                        if(dp[i] != n)
                            ans = max(ans, i + n - (dp[i] + 1) + 1);
                    } else {
                        for(int j = t[i + 1] - 'a' + 1; j < 26; ++j)
                            last = min(last, pos[dp[i] + 1][j]);
                        ans = max(ans, i + n - last + 1);
                    }
                }
            }
            printf("%d
    ", ans);
        }
    }
    
  • 相关阅读:
    Codeforces 1265A Beautiful String
    1039 Course List for Student (25)
    1038 Recover the Smallest Number (30)
    1037 Magic Coupon (25)
    1024 Palindromic Number (25)
    1051 Pop Sequence (25)
    1019 General Palindromic Number (20)
    1031 Hello World for U (20)
    1012 The Best Rank (25)
    1011 World Cup Betting (20)
  • 原文地址:https://www.cnblogs.com/Inko/p/11483758.html
Copyright © 2011-2022 走看看