• 模拟赛小结:2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)


    比赛链接:传送门

    本场我们队过的题感觉算法都挺简单的,不知道为啥做的时候感觉没有很顺利。

    封榜后7题,罚时1015。第一次模拟赛金,虽然是北欧的区域赛,但还是有点开心的。


    Problem B Best Relay Team 00:49 (+2) Solved by xk

    排序后简单模拟一下题意即可。

    xk说他要背个锅。

    代码:

    #include <iostream>
    #include <cmath>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <vector>
    #include <string>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #ifdef ONLINE_JUDGE
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #else
    #define fast 
    #endif
    #define forn(i, n) for(int i = 0; i < (n); i++)
    #define forab(i, a, b) for(int i = (a); i <= (b); i++)
    #define sz(x) ((int)x.size())
    #define upperdiv(a,b) (a/b + (a%b>0))
    #define mp(a,b) make_pair(a, b)
    #define endl '
    '
    #define lowbit(x) (x&-x)
    
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    const int maxn = 500 + 5;
    
    string s[maxn];
    db a[maxn], b[maxn];
    
    int main()
    {
        int n;
        fast;
        cin >> n;
        forn(i, n)
        {
            cin >> s[i] >> a[i] >> b[i];
        }
        vector<pair<db, int> > va, vb;
        forn(i, n)
        {
            va.push_back(mp(a[i], i));
            vb.push_back(mp(b[i], i));
        }
        sort(va.begin(), va.end());
        sort(vb.begin(), vb.end());
        db ans =  1e100;
        int aid = 0;
        int isin = 0;
        forn(i, n)
        {
            db temp = a[i];
            int in3 = 0;
            forn(j, 3)
            {
                if(i == vb[j].second) {
                    in3 = 1;
                    continue;
                }
                temp += vb[j].first;
            }
            if(in3) temp += vb[3].first;
            if(temp < ans) {
                aid = i;
                isin = in3;
                ans = temp;
            }
        }
        cout << ans << endl;
        cout << s[aid] << endl;
        forn(i, 3)
        {
            if(aid != vb[i].second)
                cout << s[vb[i].second] << endl;
        }
        if(isin)
            cout << s[vb[3].second] << endl;
        return 0;
    }
    View Code

    Problem D Distinctive Character 03:52 (+) Solved by xk (bfs)

    类似于bfs的想法,每个状态走一步可以到达的状态是二进制与其有1位不同的状态。最后一个出队的点就是答案。所有状态空间是$2^{20} ≈ 10^{6}$。

    我和lh盯了好久没有思路,几乎要弃题了。结果xk一拍脑门就来了一发bfs就过了。

    代码:$O(2^{k})$

    #include <iostream>
    #include <cmath>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <vector>
    #include <string>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #include <bitset>
    #ifdef ONLINE_JUDGE
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #else
    #define fast 
    #endif
    #define forn(i, n) for(int i = 0; i < (n); i++)
    #define forab(i, a, b) for(int i = (a); i <= (b); i++)
    #define sz(x) ((int)x.size())
    #define upperdiv(a,b) (a/b + (a%b>0))
    #define mp(a,b) make_pair(a, b)
    #define endl '
    '
    #define lowbit(x) (x&-x)
    
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    const int maxk = (1 << 20) + 5;
    const int maxn = 1e5 + 5;
    
    int dep[maxk];
    int a[maxn];
    
    int main()
    {
        fast;
        int n, k;
        cin >> n >> k;
        forn(i, n)
        {
            char s[30];
            cin >> s;
            forn(j, k)
            {
                a[i] = a[i] * 2 + s[j] - '0';
            }
        }
        sort(a, a + n);
        n = unique(a, a + n) - a;
        queue<int> q;
        memset(dep, -1, sizeof(dep));
        forn(i, n)
        {
            q.push(a[i]);
            dep[a[i]] = 0;
        }
        int ans = a[0];
        while(!q.empty())
        {
            int x = q.front(); q.pop();
            forn(i, k)
            {
                int y = x ^ (1 << i);
                // cout << bitset<5>(x) << ' ' << bitset<5>(y) << ' ' << dep[y] << endl;
                if(dep[y] == -1)
                {
                    dep[y] = dep[x] + 1;
                    if(dep[y] > dep[ans])
                    {
                        ans = y;
                    }
                    q.push(y);
                }
                // cout << bitset<5>(x) << ' ' << bitset<5>(y) << ' ' << dep[y] << endl;
            }
        }
        for(int i = k - 1; i >= 0; i--)
        {
            cout << (bool)(ans & (1 << i));
        }
        return 0;
    }
    View Code

    Problem E Emptying the Baltic 02:25(+) Solved by Dancepted (优先队列 + bfs)

    每次挑海拔最低的点进行bfs,每个点的海拔更新为max(原来的海拔,bfs过来的点的海拔)。因为每次选的是最低的点进行bfs,所以能保证每个点第一次被更新时一定是最优的。

    看了半个多小时才看出来做法,太菜了qwq。

    代码:$O(hw)$

    #include <iostream>
    #include <cmath>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <vector>
    #include <string>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #define N 505
    #define M 100005
    #define INF 0x3f3f3f3f
    #define mk(x) (1<<x) // be conscious if mask x exceeds int
    #define sz(x) ((int)x.size())
    #define upperdiv(a,b) (a/b + (a%b>0))
    #define mp(a,b) make_pair(a, b)
    #define endl '
    '
    #define lowbit(x) (x&-x)
    
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    /** fast read **/
    template <typename T>
    inline void read(T &x) {
        x = 0; T fg = 1; char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') fg = -1;
            ch = getchar();
        }
        while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
        x = fg * x;
    }
    template <typename T, typename... Args>
    inline void read(T &x, Args &... args) { read(x), read(args...); }
    template <typename T>
    inline void write(T x) {
        int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
        do{++len; c[len] = x%10 + '0';} while (x /= 10);
        for (int i = len; i >= 1; i--) putchar(c[i]);
    }
    template <typename T, typename... Args>
    inline void write(T x, Args ... args) { write(x), write(args...); }
    
    const int dx[8] = {1, 1, 1, 0, -1, -1, -1, 0};
    const int dy[8] = {1, 0, -1, -1, -1, 0, 1, 1};
    
    struct Node{
        int x, y;
        ll dep;
        bool operator < (const Node& x) const {
            return dep > x.dep;
        }
    };
    ll pool[N][N];
    bool vis[N][N];
    priority_queue <Node> Q;
    int main() {
        int n, m; cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++)
                read(pool[i][j]);
        }
        Node st;
        read(st.x, st.y);
        st.dep = pool[st.x][st.y];
        Q.push(st);
        while (!Q.empty()) {
            Node tmp = Q.top(); Q.pop();
            if (vis[tmp.x][tmp.y])
                continue;
            vis[tmp.x][tmp.y] = true;
            pool[tmp.x][tmp.y] = tmp.dep;
            for (int i = 0; i < 8; i++) {
                Node nxt = Node{tmp.x + dx[i], tmp.y + dy[i]};
                if (nxt.x <= 0 || nxt.x > n || nxt.y <= 0 || nxt.y > m)
                    continue;
                if (vis[nxt.x][nxt.y])
                    continue;
                nxt.dep = max(pool[nxt.x][nxt.y], tmp.dep);
                Q.push(nxt);
            }
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (pool[i][j] < 0)
                    ans -= pool[i][j];
            }
        }
        cout << ans << endl;
        return 0;
    }
    View Code

    Problem G Galactic Collegiate Programming Contest 02:16(+) Solved by xk (模拟)

    比赛中的大致思路是开M个set,对应每个解题数的队伍。如果如果其他队过题,观察题数/罚时是否超过了1号队。如果是1号队过题,算上过题数和罚时之后,在对应的题数里面暴力找1号队的排名。

    复杂度的期望是O(nlogn)的,常数比较大,不过关系不大。

    代码:$O(nlogn)$

    #include <iostream>
    #include <cmath>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <vector>
    #include <string>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #ifdef ONLINE_JUDGE
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #else
    #define fast 
    #endif
    #define forn(i, n) for(int i = 0; i < (n); i++)
    #define forab(i, a, b) for(int i = (a); i <= (b); i++)
    #define sz(x) ((int)x.size())
    #define upperdiv(a,b) (a/b + (a%b>0))
    #define mp(a,b) make_pair(a, b)
    #define endl '
    '
    #define lowbit(x) (x&-x)
    
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    const int maxn = 1e5 + 5;
    
    struct node
    {
        int solve, time;
        bool operator < (const node & a) const
        {
            if(solve != a.solve) return solve < a.solve;
            return time > a.time;
        }
    };
    
    int n, m;
    set<pair<int, int> > s[maxn];
    int sum[maxn];
    int solve[maxn], penal[maxn];
    
    int main()
    {
        fast;
        cin >> n >> m;
        int ans = 1;
        forab(i, 1, n)
        {
            s[0].insert(mp(0, i));
            sum[i] = n;
        }
        for (int i = 1; i <= m; i++)
        {
            int t, p;
            cin >> t >> p;
            s[solve[t]].erase(mp(penal[t], t));
            sum[solve[t]]--;
            solve[t]++; penal[t] += p;
            s[solve[t]].insert(mp(penal[t], t));
            
            if(t == 1)
            {
                auto it = s[solve[t]].begin();
                ans = n - sum[solve[t]] + 1;
                while(it->first < penal[t])
                {
                    ans++;
                    it++;
                }
            }
            else
            {
                node t1 = node{solve[1], penal[1]};
                node before = node{solve[t] - 1, penal[t] - p};
                node now = node{solve[t], penal[t]};
                if(!(t1 < before) && t1 < now)
                {
                    ans++;
                }
            }
            cout << ans << endl;
        }
        return 0;
    }
    /*
    3 4
    2 7
    3 5
    1 6
    1 9
    */
    View Code

    赛后观摩了一下claris的博客,有个更好的模拟。

    维护一个set表示比1号队排名严格靠前的队伍。其他队过题就考虑是否加入set,1队过题就考虑在set中删除被1队超过的队伍。

    代码:$O(nlogn)$

    #include <iostream>
    #include <cmath>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <stdio.h>
    #include <vector>
    #include <string>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #define N 100005
    #define M 100005
    #define INF 0x3f3f3f3f
    #define mk(x) (1<<x) // be conscious if mask x exceeds int
    #define sz(x) ((int)x.size())
    #define upperdiv(a,b) (a/b + (a%b>0))
    #define mp(a,b) make_pair(a, b)
    #define endl '
    '
    #define lowbit(x) (x&-x)
    
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    /** fast read **/
    template <typename T>
    inline void read(T &x) {
        x = 0; T fg = 1; char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') fg = -1;
            ch = getchar();
        }
        while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
        x = fg * x;
    }
    template <typename T, typename... Args>
    inline void read(T &x, Args &... args) { read(x), read(args...); }
    template <typename T>
    inline void write(T x) {
        int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
        do{++len; c[len] = x%10 + '0';} while (x /= 10);
        for (int i = len; i >= 1; i--) putchar(c[i]);
    }
    template <typename T, typename... Args>
    inline void write(T x, Args ... args) { write(x), write(args...); }
    
    struct Node{
        int id, cnt, penalty;
        bool operator < (const Node& x) const {
            if(cnt == x.cnt) {
                if (penalty == x.penalty)
                    return id < x.id;
                return penalty < x.penalty;
            }
            return cnt > x.cnt;
        }
    };
    set<Node> S;
    set<Node> :: iterator it, jt;
    int cnt[N], penalty[N];
    int main() {
        int n, m; cin >> n >> m;
        Node concern = Node{1, 0, 0};
        for (int i = 1; i <= m; i++) {
            int t, p; read(t, p);
            if (t == 1) {
                concern.cnt++;
                concern.penalty += p;
                it = S.lower_bound(concern);
                while (it != S.end()) {
                    jt = it++;
                    S.erase(jt);
                }
            }
            else {
                Node pre = Node{t, cnt[t], penalty[t]};
                cnt[t]++, penalty[t] += p;
                Node nxt = Node{t, cnt[t], penalty[t]};
                if (pre < concern)
                    S.erase(pre);
                if (nxt < concern)
                    S.insert(nxt);
            }
            printf("%d
    ", sz(S) + 1);
        }
        return 0;
    }
    View Code

    Problem I Import Spaghetti 01:31(+) Solved by lh (floyd)

    实际上就是找出一个有向图的最小环。$dis_{i,i}$初始化为INF,跑一下floyd之后,找$dis_{i,i}$的最小值。

    代码:$O(n^{3})$

    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <map>
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #define N 100005
    #define M 100005
    #define INF 0x3f3f3f3f
    using namespace std;
    int n, dis[505][505], k, road[505][505];
    map<string, int> id;
    map<int, string> in;
    string s;
    int final[N], tot = 0;
    void solve(int l, int r)
    {
        if(dis[l][r] == 1)
            return;
        solve(l, road[l][r]), final[++tot] = road[l][r], solve(road[l][r], r);
    }
    int ac()
    {
        fast;
        cin >> n;
        memset(dis, 0x3f, sizeof(dis));
        for(int i = 1; i <= n; ++i)
            cin >> s, id[s] = i, in[i] = s;
        for(int i = 1; i <= n; ++i)
        {
            cin >> s >> k;
            char c;
            for (int j = 1; j <= k; ++j)
            {
                cin >> s >> s;
                while (s[s.size() - 1] == ',')
                {
                    s.pop_back();
                    dis[i][id[s]] = 1;
                    cin >> s;
                }
                dis[i][id[s]] = 1;
            }
        }
        for (int i = 1;i <= n; ++i)
            for (int j = 1;j <= n; ++j)
                for (int k = 1;k <= n; ++k)
                {
                    if (dis[j][k] > dis[j][i] + dis[i][k])
                        dis[j][k] = dis[j][i] + dis[i][k], road[j][k] = i;
                }
        int ans = 1;
        bool flag = false;
        for (int i = 1;i <= n; ++i)
        {
            if (dis[i][i] != INF)
            {
                flag = true;
                if (dis[ans][ans] > dis[i][i])
                    ans = i;
            }
        }
        if (!flag)
        {
            puts("SHIP IT");
            return 0;
        }
        solve(ans, ans), cout << in[ans];
        for (int i = 1; i <= tot; ++i)
            cout << " " << in[final[i]];
    }
    int main()
    {
        ac();
        return 0;
    }
    /*
    4
    a b c d
    a 1
    import d, b, c
    b 2
    import d
    import c
    c 1
    import c
    d 0
    */
    View Code

    Problem J Judging Moose 00:12 (+) Solved by Dancepted

    printf级别的签到。12分钟才过是因为电脑网速太慢打不开pdf。

    代码:

    View Code

     

    Problem K Kayaking Trip 04:30 (-2) Solved by Dancepted (二分答案+贪心)

    答案单调是显然的。贪心就是对每艘船选择最小的选手能力值的组合,使得这个组合与船的系数的乘积,能不小于答案。

    读完题我就猜是这么写的,但是正确性有点不确定。然后lh想了个假的暴力交上去wa了两发后,被我hack了。

    代码(附一个样例):$O((b+n+e)log(2 * c_{max} * s_{max})$

    #include <iostream>
    #include <cmath>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <vector>
    #include <string>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    #define N 100005
    #define M 100005
    #define INF 0x3f3f3f3f
    #define mk(x) (1<<x) // be conscious if mask x exceeds int
    #define sz(x) ((int)x.size())
    #define upperdiv(a,b) (a/b + (a%b>0))
    #define mp(a,b) make_pair(a, b)
    #define endl '
    '
    #define lowbit(x) (x&-x)
    
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    /** fast read **/
    template <typename T>
    inline void read(T &x) {
        x = 0; T fg = 1; char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') fg = -1;
            ch = getchar();
        }
        while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
        x = fg * x;
    }
    template <typename T, typename... Args>
    inline void read(T &x, Args &... args) { read(x), read(args...); }
    template <typename T>
    inline void write(T x) {
        int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
        do{++len; c[len] = x%10 + '0';} while (x /= 10);
        for (int i = len; i >= 1; i--) putchar(c[i]);
    }
    template <typename T, typename... Args>
    inline void write(T x, Args ... args) { write(x), write(args...); }
    
    int sum = 0;
    int cnt[3], val[3], boat[N];
    int ccnt[3];
    bool check(int mid) {
        for (int i = 0; i < 3; i++)
            ccnt[i] = cnt[i];
        for (int i = 0; i < sum/2; i++) {
            int pa = 2, pb = 2;
            for (int a = 0; a < 3; a++) if (ccnt[a]) {
                ccnt[a]--;
                for (int b = a; b < 3; b++) if (ccnt[b]) {
                    ccnt[b]--;
                    if (mid <= boat[i] * (val[a] + val[b]) && val[a] + val[b] < val[pa] + val[pb]) {
                        pa = a;
                        pb = b;
                    }
                    ccnt[b]++;
                }
                ccnt[a]++;
            }
            if (mid > boat[i] * (val[pa] + val[pb]))
                return false;
            if (pa != pb) {
                if (ccnt[pa] && ccnt[pb]) {
                    ccnt[pa]--, ccnt[pb]--;
                }
                else
                    return false;
            }
            else if (pa == pb) {
                if (ccnt[pa] >= 2) {
                    ccnt[pa] -= 2;
                }
                else
                    return false;
            }
        }
        return true;
    }
    
    int main() {
        for (int i = 0; i < 3; i++)
            read(cnt[i]),
            sum += cnt[i];
        for (int i = 0; i < 3; i++)
            read(val[i]);
        for (int i = 0; i < sum/2; i++) {
            read(boat[i]);
        }
        sort(boat, boat + sum/2);
        int l = 0, r = INF, ans = 0;
        // int l = 0, r = 5000, ans = 0;
        while (l <= r) {
            int mid = (l+r) >> 1;
            if (check(mid)) {
                ans = max(ans, mid);
                l = mid+1;
            }
            else {
                r = mid-1;
            }
        }
        cout << ans << endl;
        return 0;
    }
    /*
    4 4 4
    1 2 5
    42 60 70 105 140 210
    */
    View Code

    总结

    封榜的时候已经没事干了,我抓起键盘想着莽一发K的二分+贪心,居然真的就过了。模拟赛拿金成就get√。

    第一次模拟赛金着实开心,但是想了想这场打得也不是很舒服,也没有发挥得很好。前期开题各种不顺,但是看排名就是掉不下去。可能是这个赛区的选手弱了吧。

    上海站还有10天不到的时间,理论上是能冲到银首的位置的。就看能不能开出一道金牌题了。

    接下来几天看看进阶指南,学点没学过的算法,打完ccpcf回来再练几场模拟赛,应该就差不多了。

    2019冲鸭!

  • 相关阅读:
    4.6--4.9
    4.表达式和运算符
    3.9--3.10
    3.8
    泛型(Generic)
    容器
    String,StringBuffer
    数组
    异常,自定义异常,异常重写
    多态,抽象类和抽象方法,接口
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/11848149.html
Copyright © 2020-2023  润新知