zoukankan      html  css  js  c++  java
  • 2019 ICPC 南昌 (C E G L)

    https://vjudge.net/contest/440183#overview

    当天过了两道,一个签到的简单模拟(L),还有一个最大生成树(E).

    C - And and Pair

    给出长度为1e5的01串,要求满足:

     的(i,j)有多少对.

    数学题,运用排列组合,推导过程里出现了二项式定理.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <string>
    using namespace std;
    #define M 1000000007
    
    string s;
    
    long long ksm(long long b, long long p){
        long long ans = 1 % M;
        while(p){
            if(p & 1) ans = (long long)ans * b % M;
            b = (long long)b * b % M;
            p >>= 1;
        }
        return ans;
    }
    
    void solve(){
        cin >> s;
        reverse(s.begin(), s.end());
        long long ct1 = 0, ct0 = 0, ans = 0;
        for(auto i = s.begin(); i != s.end(); i++){
            auto c = *i;
            if(c == '1') {
                ans = (ans + ksm(3, ct1) * ksm(2, ct0)) % M;
                ct1++;
            }else ct0++;
        }
        printf("%lld
    ", ans + 1);
    }
    
    int main(){
        int t;
        scanf("%d", &t);
        while(t--) solve();   
    
        return 0;
    }
    C

     

    E - Bob's Problem

    最小(大)生成树,这种题目再怎么变好像都不是很难.

    可以看出来加黑边没有任何坏处,所以直接全部加上,在此后得到的图上使用Kruskal,首先检验一下在k条白边内能否得到生成树,如果不能则输出-1,否则把树生成出来,然后从大到小把剩下的(如果有)边的值加上去.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    struct E{
        int from, to, wei, col;
        bool operator<(const E&other) const {return wei > other.wei;}
    };
    vector<E> e;
    queue<int> q;
    int n, m, k, fa[50010];
    
    int get(int x) {return fa[x] == x ? x : fa[x] = get(fa[x]);}
    void merge(int x, int y) {fa[get(x)] = fa[get(y)];}
    
    void solve(){
        e.clear();
        while(!q.empty()) q.pop();
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= n; i++) fa[i] = i;
        long long ans = 0;
        while(m--){
            int u, v, w, c;
            scanf("%d%d%d%d", &u, &v, &w, &c);
            if(c == 0) {
                ans += w;
                merge(u, v);
            }else e.push_back({u, v, w, c});
        }
        sort(e.begin(), e.end());
    
        for(auto i = e.begin();k && i != e.end(); i++){
            auto cur = *i;
            if(get(cur.from) == get(cur.to)) q.push(cur.wei);
            else {
                merge(cur.from, cur.to);
                ans += cur.wei;
                k--;
            }
        }
        while(k-- && !q.empty()){
            ans += q.front();
            q.pop();
        }
    
        int ct = 0;
        for(int i = 1; i <= n; i++) if(fa[i] == i) ct++;
        if(ct == 1)
            printf("%lld
    ", ans);
        else
            puts("-1");
    }
    
    int main(){
        int t;
        scanf("%d", &t);
        while(t--) solve();   
    
        return 0;
    }
    E

    G - Eating Plan

     将一个1~n的排列中的每个数转化为其对应的阶乘,得到一个序列.要求从中选择连续的一段,使得该段上的值的和对998857459取模后不小于给定的k(序列不变,对k进行m次询问).

    n,m均为1e5.

    可以想一想,如果不考虑序列内都是排列的阶乘这一性质,即序列中的数是无规律的,这一问题可能没有合理的时间复杂度的求解方法.

    答案是,这个模数有猫腻.

    如果用下面的方法分解一下998857459的因数:

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <set>
    using namespace std;
    
    int t = 998857459;
    set<int> s;
    
    int main(){
        for(int i = 2; i < 10000000; i++)
            while(t % i == 0) t /= i, s.insert(i);
        for(auto i : s) cout << i << endl;
    
        return 0;
    }
    分解因数

    会得到

    461 
    773 
    2803

    这意味着对于一个x>=2803,x!=1*2*3*...*461*...*773*...*2803*...*x,其对998857459取模后为0.

    因此不管n有多大,最多有2803个值不是0,对于为0的数是很好处理的.

    这种题目算是用来开眼界吧.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    struct E{
        int from, to, wei, col;
        bool operator<(const E&other) const {return wei > other.wei;}
    };
    vector<E> e;
    queue<int> q;
    int n, m, k, fa[50010];
    
    int get(int x) {return fa[x] == x ? x : fa[x] = get(fa[x]);}
    void merge(int x, int y) {fa[get(x)] = fa[get(y)];}
    
    void solve(){
        e.clear();
        while(!q.empty()) q.pop();
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= n; i++) fa[i] = i;
        long long ans = 0;
        while(m--){
            int u, v, w, c;
            scanf("%d%d%d%d", &u, &v, &w, &c);
            if(c == 0) {
                ans += w;
                merge(u, v);
            }else e.push_back({u, v, w, c});
        }
        sort(e.begin(), e.end());
    
        for(auto i = e.begin();k && i != e.end(); i++){
            auto cur = *i;
            if(get(cur.from) == get(cur.to)) q.push(cur.wei);
            else {
                merge(cur.from, cur.to);
                ans += cur.wei;
                k--;
            }
        }
        while(k-- && !q.empty()){
            ans += q.front();
            q.pop();
        }
    
        int ct = 0;
        for(int i = 1; i <= n; i++) if(fa[i] == i) ct++;
        if(ct == 1)
            printf("%lld
    ", ans);
        else
            puts("-1");
    }
    
    int main(){
        int t;
        scanf("%d", &t);
        while(t--) solve();   
    
        return 0;
    }
    E

    L - Who is the Champion

    签到,排个序就好.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    int n, G[110][110];
    struct T{
        int num, dif, sco;
        bool operator<(const T& other) const {if(sco != other.sco) return sco > other.sco; return dif > other.dif;}
    }t[110];
    
    int main(){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++){
                scanf("%d", &G[i][j]);
                t[i].dif += G[i][j];
                t[j].dif -= G[i][j];
                t[i].num = i;
            }
    
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++){
                if(G[i][j] > G[j][i]) t[i].sco += 3;
                else if(G[i][j] == G[j][i]) t[i].sco += 1;
            }
    
        sort(t + 1, t + 1 + n);
        if(t[1].sco == t[2].sco && t[1].dif == t[2].dif) puts("play-offs");
        else printf("%d
    ", t[1].num);
    
        return 0;
    }
    L
  • 相关阅读:
    BNUOJ 12756 Social Holidaying(二分匹配)
    HDU 1114 Piggy-Bank(完全背包)
    HDU 2844 Coins (多重背包)
    HDU 2602 Bone Collector(01背包)
    HDU 1171 Big Event in HDU(01背包)
    HDU 2571 命运 (入门dp)
    HDU 1069 Monkey and Banana(最长递减子序列)
    HDU 1160 FatMouse's Speed (最长上升子序列)
    HDU 2594 KMP
    POJ 3783 Balls --扔鸡蛋问题 经典DP
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14813099.html
Copyright © 2011-2022 走看看