• 模拟赛小结:The 2019 China Collegiate Programming Contest Harbin Site


    比赛链接:传送门

    上半场5题,下半场疯狂挂机,然后又是差一题金,万年银首也太难受了。

    (每次银首都会想起前队友的灵魂拷问:你们队练习的时候进金区的次数多不多啊?)


    Problem J. Justifying the Conjecture 00:09 (+) Solved by Dancepted

    签到。好像见过很多次了,经典水题。然后英语太差了,理解题意用了不少时间。

    代码:

    #include <bits/stdc++.h>
    #define endl '
    '
     
    using namespace std;
     
    int main() {
        int T;
        cin >> T;
        while (T--) {
            int x;
            scanf("%d", &x);
            if (x <= 5) {
                puts("-1");
                continue;
            }
            else if (x&1) {
                cout << 3 << ' ' << x - 3 << endl;
            }
            else {
                cout << 2 << ' ' << x - 2 << endl;
            }
        }
     
        return 0;
    }
    View Code

     

    Problem K. Keeping Rabbits 00:09 (-1) Solved by Dancepted

    签到。稍微想一下发现期望重量跟第一天的重量线性相关,把所有的胡萝卜按重量分配即可。

    因为担心不必要的精度问题用了long double结果交上去不知道为啥输出了-0.000000,WA了一发。

    代码:

    #include <bits/stdc++.h>
    #define N 100005
     
    using namespace std;
    typedef double db;
     
    db w[N];
     
    int main() {
        int T;
        cin >> T;
        while (T--) {
            int n, k;
            scanf("%d%d", &n, &k);
            db sum = 0;
            for (int i = 1; i <= n; i++) {
                scanf("%lf", &w[i]);
                sum += w[i];
            }
            for (int i = 1; i <= n; i++) {
                w[i] += (db)k*w[i]/sum;
                printf("%.6f%c", w[i], " 
    "[i == n]);
            }
        }
        return 0;
    }
    View Code

     

    Problem F. Fixing Banners 00:36 (+) Solved by lh

    签到。暴力枚举。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define lowbit(x) ((-x) & x)
    #define ffor(i, d, u) for (int i = (d); i <= (u); ++i)
    #define _ffor(i, u, d) for (int i = (u); i >= (d); --i)
    #define mst(array, Num, Kind, Count) memset(array, Num, sizeof(Kind) * (Count))
    #define mp(x, y) make_pair(x, y)
    #define fi first
    #define se second
    typedef long long ll;
    typedef double db;
    typedef pair<ll, ll> pll;
    typedef pair<int, int> pii;
    typedef pair<db, db> pdd;
    const db PI = acos(-1);
    template <typename T>
    inline void read(T &x)
    {
        x=0;char c;T t=1;while(((c=getchar())<'0'||c>'9')&&c!='-');
        if(c=='-'){t=-1;c=getchar();}do(x*=10)+=(c-'0');while((c=getchar())>='0'&&c<='9');x*=t;
    }
    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*=(-1);
        do{++len;c[len]=(x%10)+'0';}while(x/=10);_ffor(i,len,1)putchar(c[i]);
    }
    const ll MO = 1e9 + 7;
    const ll Inv2 = (MO + 1) / 2;
    #define N 2000005
    #define M 3000005
    int T, cnt[6][6];
    char a[6][N], mu[6] = {'h', 'a', 'r', 'b', 'i', 'n'};
    bool flag[6] = {};
    inline int ac()
    {
        read(T);
        while (T--)
        {
            int b[6] = {0, 1, 2, 3, 4, 5};
            ffor(i, 0, 5)
            {
                scanf("%s", a[i]);
                ffor(j, 0, 5) cnt[i][j] = 0;
            }
            ffor(i, 0, 5)
            {
                int len = strlen(a[i]) - 1;
                ffor(j, 0, len)
                {
                    switch(a[i][j])
                    {
                        case 'h':
                            ++cnt[i][0];
                            break;
                        case 'a':
                            ++cnt[i][1];
                            break;
                        case 'r':
                            ++cnt[i][2];
                            break;
                        case 'b':
                            ++cnt[i][3];
                            break;
                        case 'i':
                            ++cnt[i][4];
                            break;
                        case 'n':
                            ++cnt[i][5];
                            break;
                    }
                }
            }
            bool flag = false;
            do
            {
                int tot = 0;
                ffor(i, 0, 5) if (cnt[b[i]][i] > 0)++ tot;
                else break;
                if (tot == 6)
                {
                    flag = true;
                    break;
                }
            } while (next_permutation(b, b + 6));
            puts(flag ? "Yes" : "No");
        }
        return 0;
    }
    int main()
    {
        ac();
        return 0;
    }
    View Code

     

    Problem I. Interesting Permutation 01:48 (-1) Solved by Dancepted

    不考虑a1是什么,而是考虑$a_{i}和a_{i-1}$之间的相对大小关系。

    如果h序列是合法的话,最后n个数肯定是占据数轴上的一段长度为n的区间,这时再移动a1使得所有的数都落在[1, n]。

    考虑h序列相邻两项

    ①$h_{i} < h_{i-1}$,不存在这样的序列,答案为0

    ②$h_{i} > h_{i-1}$,$a_{i}$比之前的最大值大$h_{i} - h_{i-1}$,或比之前的最小值小$h_{i} - h_{i-1}$,仅这两种选择,所以。

    ③$h_{i} = h_{i-1}$,$a_{i}$落在之前的最大值和最小值之间,选择的方案数为:[最小值,最大值]的区间长度 - $a_{i}$之前的数的个数(i - 1)

    (WA了一发是因为脑抽把1e9+7写成了1e9+9,害得队友帮我写了一发暴力对拍了超久)

    代码:O(n)

    #include <bits/stdc++.h>
    #define N 100005
    #define md 1000000007
     
    using namespace std;
    typedef double db;
    typedef long long ll;
     
    int h[N];
     
    int main() {
        int T;
        cin >> T;
        while (T--) {
            int n;
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                scanf("%d", &h[i]);
            }
            ll ans = 1;
            if (h[1] != 0 || h[n] != n-1)
                ans = 0;
            for (int i = 2; i <= n; i++) {
                if (h[i] < h[i-1]) {
                    ans = 0;
                }
                else if (h[i] == h[i-1]) {
                    ans = ans * (h[i] + 1 - (i - 1)) % md;
                }
                else if (h[i] > h[i-1]) {
                    ans = ans * 2 % md;
                }
     
                if (h[i]+1 <= i-1)
                    ans = 0;
                if (ans == 0)
                    break;
            }
     
            cout << ans << endl;
        }
        
        return 0;
    }
    View Code

     

    Problem E. Exchanging Gifts 02:19 (-1) Solved by Dancepted

    因为礼物可以任意交换,所以如果知道了最后一个序列内各个数字出现的次数总和sum和数量最多的数字的数量$cnt_{max}$,那么答案肯定就是max(sum,2 × (sum - $cnt_{max}$)。

    考虑如何统计各个数字的出现次数。

    ①如果最后一个序列是直接给出的,那么直接统计即可。

    ②如果最后一个序列是由之前的两个串给出的,那么对那两个串x和y分别统计。

    然后是类似dp的做法,$f_{i}$表示第i个序列被统计的次数,那么②操作就相当于$f_{x} += f_{i}, f_{y} += f_{i}$

    (WA了一发是因为f数组没有开long long,掌嘴)

    代码:O(n + $sum k$)

    #include <bits/stdc++.h>
    #define sz(x) (int)x.size()
    #define N 1000005
     
    using namespace std;
    typedef double db;
    typedef long long ll;
     
    vector<int> nums[N];
    ll mul[N];
    int x[N], y[N];
    unordered_map<int, ll> numcnt;
    unordered_map<int, ll> :: iterator it;
    int main() {
        int T;
        cin >> T;
        while (T--) {
            int n;
            scanf("%d", &n);
            numcnt.clear();
            for (int i = 1; i <= n; i++) {
                nums[i].clear();
                mul[i] = 0;
                x[i] = y[i] = -1;
            }
            mul[n] = 1;
            for (int i = 1; i <= n; i++)
            {
                int act;
                scanf("%d", &act);
                if (act == 1)
                {
                    int k;
                    scanf("%d", &k);
                    for (int j = 1; j <= k; j++)
                    {
                        int q;
                        scanf("%d", &q);
                        nums[i].push_back(q);
                    }
                }
                else if (act == 2)
                {
                    scanf("%d%d", &x[i], &y[i]);
                }
            }
            for (int i = n; i >= 1; i--) {
                if (x[i] != -1) {
                    mul[x[i]] += mul[i];
                    mul[y[i]] += mul[i];
                }
            }
     
            ll sum = 0, mx = 0;
            for (int i = 1; i <= n; i++) {
                if (x[i] == -1 && mul[i]) {
                    for (int &tmp : nums[i]) {
                        numcnt[tmp] += mul[i];
                        sum += mul[i];
                        mx = max(mx, numcnt[tmp]);
                    }
                }
            }
            ll ans = min(sum, 2 * (sum - mx));
            cout << ans << endl;
        }
        return 0;
    }
    View Code

     

    比赛结束前我还在敲B题,奈何思路太乱了,实现起来太复杂,赛后调了半天还是过不去(最后还是惨兮兮去看了题解)。


    UPD:B. Binary Numbers(dp+滚动数组优化)

    函数$F_{k}(a, b)$相当于求a,b转化成长度为m的二进制串后求最长公共前缀lcp

    然后可以发现两个数值相差越大,lcp越小。所以对于$[L_{i}, R_{i}]$这个区间,只要满足:

    ①:$lcp(A_{j}, L_{i}) <= lcp(A_{i}, L{i}),j < i$

    ②:$lcp(A_{j}, R_{i}) <= lcp(A_{i}, R{i}), j > i$

    用$f_{i, j, k}$表示考虑了前i个区间,$A_{i}$和$L_{i+1}$的lcp为j,和$R_{i}$的lcp为k的价值。

    然后暴力枚举$f_{i-1}$中满足条件的j和k进行转移即可。

    空间不够,可以滚动数组优化一下。

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

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #define N 266666
    // #define N 555
    #define M 18
     
    using namespace std;
    typedef long long ll;
    const int md = 100000007;
     
    inline int add(int a, int b) {
        int res = (a + b) % md;
        if (res < 0)
            res += md;
        return res;
    }
    inline int mul(int a, int b) {
        return (int)((ll)a * b % md);
    }
    
    inline int lcp(int a, int b, int m) {
        int res = 0;
        for (int i = m-1; i >= 0; i--) {
            if ((a & (1<<i)) == (b & (1<<i)))
                res++;
            else
                break;
        }
        return res;
    }
    
    int l[N], r[N];
    int f[2][M][M];
    int main() {
        int T;
        cin >> T;
        while (T--) {
            int m, n;
            cin >> m >> n;
            for (int i = 1; i <= n; i++)
                scanf("%d%d", &l[i], &r[i]);
            for (int i = 0; i < 2; i++) {
                for (int j = 0; j <= m; j++) {
                    for (int k = 0; k <= m; k++) {
                        f[i][j][k] = 0;
                    }
                }
            }
            for (int i = l[1]; i <= r[1]; i++) {
                int lcpl = lcp(i, l[2], m), lcpr = lcp(i, r[1], m);
                f[1][lcpl][lcpr] = add(f[1][lcpl][lcpr], i);
            }
            for (int i = 2; i <= n; i++) {
                int id = i & 1;
                memset(f[id], 0, sizeof f[id]);
                for (int j = l[i]; j <= r[i]; j++) {
                    int lcpl = lcp(j, l[i+1], m), lcpr = lcp(j, r[i], m);
                    int prelcpr = lcp(j, r[i-1], m), prelcpl = lcp(j, l[i], m);
                    for (int l1 = 0; l1 <= prelcpl; l1++) {
                        for (int r1 = prelcpr; r1 <= m; r1++) {
                            f[id][lcpl][lcpr] = add(f[id][lcpl][lcpr], mul(j, f[id^1][l1][r1]));
                        }
                    }
                }
            }
            ll ans = 0;
            for (int l = 0; l <= m; l++) {
                for (int r = 0; r <= m; r++) {
                    ans = add(ans, f[n&1][l][r]);
                }
            }
            cout << ans << endl;
        }
        return 0;
    }
    View Code

    总结:

    这场的几个罚时都不太应该,没有开long long(差点还踩了1e8+7的坑)、手滑写错了1e9+9、long double 输出-0.000000。。。

    主要刚开始上手vscode,心理上有点不适应,所以写代码的时候有点暴躁?而且用的队友的电脑,没有头文件给我复制。。。

    B题读题的时候太慢了,也是题目做的太少了,归纳能力太差劲。

    然后xk这场状态不是很好的亚子(也可能是都花时间帮我debug了,不过有一说一,xk帮我找bug确实每次都能找出来)。

    金区不像银、铜区,卡牌子的都只有一道题,开出来就高一档次,没开出来就没有。

    金区那条线的题有很多,多过一道题就能金。然鹅我们队签完到进入银区后,因为没有学得很精的算法,基本没有能开出来的金牌题,还是有点难受的。

  • 相关阅读:
    A journey on the Android Main Thread
    android的消息处理机制(图+源码分析)——Looper,Handler,Message
    用fragment创建一个选项卡
    fragment的生命周期
    动态创建fragment
    自定义自动换行布局
    Android开源框架Universal-Image-Loader完全解析(三)
    第七章 摄影技术
    第六章 镜头的成像像质评价
    第五章 镜头像差的成因,校正及规避方法
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/11790603.html
Copyright © 2020-2023  润新知