• Codeforces Edu Round 52 A-E


    A. Vasya and Chocolate

    模拟题。数据会爆(int),要开(long) (long)

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long LL;
    int main(){
        int T; scanf("%d", &T);
        while(T--){
            LL s, a, b, c;
            scanf("%lld%lld%lld%lld", &s, &a, &b, &c);
            LL buy = s / c, free = buy / a * b;
            printf("%lld
    ", buy + free);
        }
        return 0;
    }
    

    B. Vasya and Isolated Vertices

    考虑最小时,两两连边,答案为(max(n - 2 * m, 0))

    考虑最大时,除了(m)(1或0)特判以外,每次尝试用最多的边拓展一个点为不孤立的,则可以放(now - 1)条边连向之前所有的边。

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    LL n, m;
    int main(){
        cin >> n >> m;
        cout << max(n - 2 * m, 0ll) << " ";
        if(m == 0) printf("%lld
    ", n);
        else if(m == 1) printf("%lld
    ", n - 2);
        else{
            int now = 2;
            while(m - now + 1 > 0 && now < n) m -= (now - 1), now++;
            printf("%lld
    ", n - now);
        }
        return 0;
    }
    

    C. Make It Equal

    我太弱了,只想到了(O(nlogn))的做法...就是用树状数组维护前缀和,就能用(O(logn))的时间计算出代价,然后弄一个指针从大往小搜就可以了...

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <limits.h>
    typedef long long LL;
    using namespace std;
    const int N = 200010;
    int n, k, a[N], cnt[N], ans = 0, maxn = -1, minn = INT_MAX;
    LL c[N];
    void add(int x, LL k){
        for(; x <= maxn; x += x & -x) c[x] += k;
    }
    LL ask(int x){
        LL res = 0;
        for(; x; x -= x & -x) res += c[x];
        return res;
    }
    LL inline get(int x){
        return ask(maxn) - ask(x - 1);
    }
    int main(){
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++) 
            scanf("%d", a + i), cnt[a[i]]++, maxn = max(maxn, a[i]), minn = min(minn, a[i]);
        for(int i = maxn; i >= 1; i--)
            add(i, (LL)cnt[i] * i);
        for(int i = maxn; i >= 1; i--)
            cnt[i] += cnt[i + 1];
            
        int i = maxn - 1;
        while(i >= minn){
            ans++;
            while(i - 1 >= minn && get(i) - (LL)(i - 1) * cnt[i] <= k) i--;
            add(i, (LL)i * (cnt[i + 1]) - get(i + 1));
            i--;
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    其实可以在指针从上往下跳的过程中处理后缀和,所以可以用(O(n))的时间解决辣:

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <limits.h>
    typedef long long LL;
    using namespace std;
    const int N = 200010;
    int n, k, a[N], cnt[N], po[N], ans = 0, maxn = -1, minn = INT_MAX;
    LL c[N];
    int main(){
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++) 
            scanf("%d", a + i), po[a[i]]++, cnt[a[i]]++, maxn = max(maxn, a[i]), minn = min(minn, a[i]);
        for(int i = maxn; i >= 1; i--)
            cnt[i] += cnt[i + 1];
    
        int i = maxn - 1;
        c[maxn] = (LL)maxn * po[maxn];
        while(i >= minn){
            ans++;
            c[i] = c[i + 1] + (LL)i * po[i];
            while(i - 1 >= minn && c[i] - (LL)(i - 1) * cnt[i] <= k) 
                i--, c[i] = c[i + 1] + (LL)i * po[i];;
            c[i] += (LL)i * (cnt[i + 1]) - c[i + 1];
            i--;
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    D. Three Pieces

    (pair<int, int>)自带比较函数,所以省了不少功夫。写了一个优先队列(bfs)就过惹...

    一共会有$3 *N ^ 4 $个状态,每次状态扩展最多要扩展(4 * N)级别,其实还会少。

    总共复杂度为(O(12 * N ^ 5)),不会(TLE)

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    using namespace std;
    typedef pair<int, int> PII;
    const int N = 15;
    int n, a[N][N];
    PII num[N * N];
    //0: 车、1: 马: 2、象
    int dx[3][8] = {
        {1, -1, 0, 0},
        {1, 1, -1, -1, -2, -2, 2, 2},
        {1, 1, -1, -1},
    };
    int dy[3][8] = {
        {0, 0, 1, -1},
        {2, -2, 2, -2, 1, -1, 1, -1},
        {1, -1, 1, -1},
    };
    int size[3] = {4, 8, 4};
    int ne[3] = {N, 1, N};
    PII step[N][N][N * N][3];
    struct Node{
        int x, y, k, m, t, c;
    };
    bool operator < (const Node &x, const Node &y){
        return x.t == y.t ? x.c > y.c : x.t > y.t;
    }
    bool inline check(int x, int y){
        return x >= 1 && x <= n && y >= 1 && y <= n;
    }
    PII bfs(){
        priority_queue<Node> q;
        for(int i = 0; i < 3; i++){
            q.push((Node){ num[1].first, num[1].second, 1, i, 0, 0});
            step[num[1].first][num[1].second][0][i] = make_pair(0, 0);
        }
            
        while(!q.empty()){
            Node u = q.top(); q.pop();
            if(u.k >= n * n){
                return make_pair(u.t, u.c);
            }
            for(int i = 0; i < size[u.m]; i++){
                for(int j = 1; j <= ne[u.m]; j++){
                    int nx = u.x + dx[u.m][i] * j, ny = u.y + dy[u.m][i] * j;
                    int nm = u.m, nt = u.t + 1, nc = u.c;
                    int nk = (num[u.k + 1] == make_pair(nx, ny)) ? u.k + 1 : u.k;
                    PII now = make_pair(nt, nc);
                    if(!check(nx, ny)) break;
                    if(now < step[nx][ny][nk][nm]){
                        step[nx][ny][nk][nm] = now;
                        q.push((Node){nx, ny, nk, nm, nt, nc});
                    }
                }
            }
            for(int i = 0; i < 3; i++){
                if(i == u.m) continue;
                int nx = u.x, ny = u.y;
                int nm = i, nt = u.t + 1, nc = u.c + 1;
                int nk = u.k;
                PII now = make_pair(nt, nc);
                if(!check(nx, ny)) break;
                if(now < step[nx][ny][nk][nm]){
                    step[nx][ny][nk][nm] = now;
                    q.push((Node){nx, ny, nk, nm, nt, nc});
                }
            }
        }
        return make_pair(-1, -1);
    }
    int main(){
        memset(step, 0x3f, sizeof step);
        scanf("%d", &n);
        ne[0] = ne[2] = n;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                scanf("%d", &a[i][j]), num[a[i][j]] = make_pair(i, j);
        PII res = bfs();
        printf("%d %d
    ", res.first, res.second);
        return 0;
    }
    

    E. Side Transmutations

    组合数问题,我肯定是不会的...

    (A)为字符集合的长度。

    对于每一段 $ [b_{i - 1} + 1,b_i] $ $ (1 <= i <= m)$

    设这一段的长度(len = b[i] - (b[i - 1] + 1) + 1 = b[i] - b[i - 1])

    它有$A ^ {len} $种不同的选择方案:

    1. 翻过去不同,那么对应过去就有(A ^ {len} - 1) 种方案(不包括翻过去相同那种),由于可能算上等价操作,他俩算一个,所以它的贡献为 (frac{A ^ {len} * (A ^ {len} - 1)}{2})
    2. 翻过去相同,每种方案对应过去式唯一的,所以为(A ^ {len})

    这两种方案相加再(*)(ans)中即可。

    对于([b_m + 1, n - b_m])这段,选不选都不会造成重复,对答案的贡献是:

    (A ^ {n - b_m - (b _m + 1) + 1} = A ^ {n - 2 * b_m })

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long LL;
    const int MOD = 998244353;
    const int N = 200010;
    int n, m, A, b[N];
    int power(int a, int b){
        int res = 1;
        while(b){
            if(b & 1) res = (LL)res * a % MOD;
            a = (LL)a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    int main(){
        cin >> n >> m >> A;
        for(int i = 1; i <= m; i++) scanf("%d", b + i);
        LL ans = 1;
        for(int i = 1; i <= m; i++){
            LL now = power(A, b[i] - b[i - 1]);
            ans = (ans * ((now + now * (now - 1) / 2) % MOD)) % MOD;
        }
        ans = (ans * power(A, (n - 2 * b[m]))) % MOD;
        cout << ans;
        return 0;
    }
    
  • 相关阅读:
    Expression 学习 [1]
    代码格式化工具 CodeMaid
    深度复制
    Linq to entity 笔记
    Linq To SQL Update Delete
    sphinx 安装 笔记
    过滤HTML 脚本 样式 避免样式冲突
    TFS 文件显示 未下载 却无法下载到本地 文件路径版定问题解决
    生成实体文件 需要用到的SQL 语句
    应用程序 数据缓存
  • 原文地址:https://www.cnblogs.com/dmoransky/p/11269639.html
Copyright © 2020-2023  润新知