zoukankan      html  css  js  c++  java
  • Codeforces Round #695 (Div. 2)

    A. Wizard of Orz

    大意:

    有n个时钟,都从0开始计时,每秒都会集体+1,如果当前是9,那么下一秒会变成0

    现在可以在任意时间选择一个位置,使这个位置上的时钟停下来,然后过一秒钟后,相邻两个时钟会停下来,再过一秒钟后,再向外的两个时钟会停下来.....

    最后全部的时钟停下来后,所有的数字可以组成一个长度为n的数,问这个数最大是多少

    思路:

    为了使数字最大,那么肯定是希望第一个位置在9停下,然后第二个位置相应的在8停下,如果一开始选择的是第二个位置,那么可以使第三位为9,此时数字最大

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    typedef long long LL;
    int t, n;
    int main() {
        cin >> t;
        while (t--) {
            cin >> n;
            if (n == 1)
                cout << 9;
            else if (n == 2)
                cout << 98;
            else if (n == 3)
                cout << 989;
            else {
                cout << 989;
                for (int i = 0; i < n - 3; i++) {
                    cout << i % 10;
                }
            }
            cout << endl;
        }
        return 0;
    }
    

    B. Hills And Valleys

    大意:

    给出n个数,现在定义若(a[i-1]>a[i])(a[i]<a[i+1])或者(a[i-1]<a[i])(a[i]>a[i+1]),则数列的威胁值+1

    现在可以任选一个数,将其变为任意一个数,从而得到数列的一个新的威胁值,问这个威胁值最少可以是多少

    思路:

    因为必须是严格上升或者下降才能+1,所以如果将(a[i])改为(a[i-1])或者(a[i+1]),就会使得分数变化,而修改一个位置上的数,最多会影响三个位置的取值,所以只需要枚举一下修改的位置即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 3e5 + 5;
    typedef long long LL;
    int t, n;
    int a[N];
    
    int judge(int pos) {
        if (pos == 0 || pos == n - 1) return 0;
        if ((a[pos - 1] > a[pos]) && (a[pos + 1] > a[pos])) return 1;
        if ((a[pos - 1] < a[pos]) && (a[pos + 1] < a[pos])) return 1;
        return 0;
    }
    
    int main() {
        cin >> t;
        while (t--) {
            cin >> n;
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
            int sum = 0;
            int mx = 0;
            for (int i = 0; i < n; i++) {
                sum += judge(i);
                if (i != 0 && i != n - 1) {
                    int tmp = 0;
                    int ori = 0;
                    tmp = judge(i - 1) + judge(i) + judge(i + 1);
                    int pre = a[i];
                    ori = tmp;
                    a[i] = a[i - 1];
                    tmp = min(tmp,judge(i - 1) + judge(i) + judge(i + 1));
                    a[i] = a[i + 1];
                    tmp = min(tmp,judge(i - 1) + judge(i) + judge(i + 1));
                    mx = max(mx, ori - tmp);
                    a[i] = pre;
                }
            }
            cout << sum - mx << endl;
        }
        return 0;
    }
    

    C. Three Bags

    大意:

    给出三个背包,每个背包里有几个数字

    每次操作可以从两个不同的背包里面各取出一个数字a和b,然后令a=a-b,然后把a放回去,b丢弃

    问最后只剩下一个数时,这个数最大为多少

    思路:

    假设背包的编号为abc

    两种情况:

    一种是先将b1到bn全挂到a1上,然后把c2到cn全挂到a1上,最后把a1到an全挂到c1上,这样就是a数组全部取负,b和c数组全部为正

    一种是留出b和c中最小的那个数取负,其他都取正即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 3e5 + 5;
    typedef long long LL;
    int n[3];
    LL a[3][N], minx[3], sum[3];
    int main() {
        for (int i = 0; i < 3; i++) cin >> n[i];
        for (int i = 0; i < 3; i++) {
            minx[i] = 0x3f3f3f3f;
            sum[i] = 0;
            for (int j = 0; j < n[i]; j++) {
                cin >> a[i][j];
                minx[i] = min(minx[i], a[i][j]);
                sum[i] += a[i][j];
            }
        }
        LL res = -0x3f3f3f3f;
        for (int i = 0; i < 3; i++) {
            LL tmp = 0;
            for (int j = 0; j < 3; j++) {
                if (i == j)
                    tmp -= sum[j];
                else
                    tmp += sum[j];
            }
            res = max(res, tmp);
            //cout << tmp << endl;
        }
        for (int i = 0; i < 3; i++) {
            LL tmp = 0;
            for (int j = 0; j < 3; j++) {
                if (i == j)
                    tmp += sum[j];
                else
                    tmp += sum[j]-2*minx[j];
            }
            res = max(res, tmp);
            //cout << tmp << endl;
        }
        cout << res << endl;
        return 0;
    }
    

    D. Sum of Paths

    大意:

    一个长度为n的数轴,一个机器人在从任意一个位置开始,走k步,每步都可以向左或向右走1步。

    走k步之后会得到一条轨迹,轨迹的权值就是每个点的权值和,那么对于这个长度为n的数轴,就可以求出所有轨迹的权值和。

    现在给出m次修改,将x位置上的权值改为y,输出每一次修改后的所有轨迹的权值和

    思路:

    首先(dp[i][j])代表在第j步走到第i位置的方案数,转移方程为:

    (dp[i][j]=dp[i+1][j-1]+dp[i-1][j-1])

    然后计算(c[i])代表第i个位置上的数贡献了多少次:

    $c[j] += dp[j][i] * dp[j][k - i] $

    此时(dp[j][k - i])代表从j这里走出去k-i次的方案数,因为和别的地方走k-i次到j处的方案数相同,所以可以直接用

    最后就是每次计算权值和即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 5e3 + 5;
    typedef long long LL;
    int n, k, m;
    const int mod = 1e9 + 7;
    LL a[N], dp[N][N], c[N], sum = 0;
    int main() {
        cin >> n >> k >> m;
        for (int i = 1; i <= n; i++) dp[i][0] = 1;
        for (int i = 1; i <= k; i++) {
            for (int j = 1; j <= n; j++) {
                if (j == 1)
                    dp[j][i] = dp[j + 1][i - 1];
                else if (j == n)
                    dp[j][i] = dp[j - 1][i - 1];
                else
                    dp[j][i] = (dp[j - 1][i - 1] + dp[j + 1][i - 1])%mod;
            }
        }
        for (int i = 0; i <= k; i++) {
            for (int j = 1; j <= n; j++) {
                c[j] += dp[j][i] * dp[j][k - i] % mod;
                c[j] %= mod;
            }
        }
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sum += a[i] * c[i] % mod;
            sum %= mod;
        }
        while(m--){
            int x,y;
            cin>>x>>y;
            sum -= a[x] * c[x] % mod;
            sum = (sum + mod) % mod;
            a[x] = y;
            sum += a[x] * c[x] % mod;
            sum = (sum + mod) % mod;
            cout << sum << endl;
        } return 0;
    }
    

    E. Distinctive Roots in a Tree

    大意:

    定义一个点为distinctive roots,如果从从这个点到树上其他点的路径中,所有的权值只出现过一次。

    求出distinctive roots的个数

    思路:

    直接求哪个点是distinctive roots没有思路,可以考虑删去全部不符合条件的点,剩下的都是distinctive roots

    先随便找一个点开始dfs,然后对于每个点,如果子树中存在和这个点的权值相同的点,那么这个点的其他子树都不能符合条件,而且这个点之上的所有点都不符合条件。

    如果这个和这个点权值相同的点不全在子树上,那么这个点的所有子树都不符合条件

    这两种情况通过树上差分标记一下即可,需要注意的是第一种情况难以直接全标记出来,可以结合第二种情况进行标记

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 2e5 + 5;
    typedef long long LL;
    int n, w[N], c[N], xu[N], cnt = 0,num,have[N],ed[N],total[N];
    vector<int> mp[N];
    map<int, int> Hash;
    void dfs(int now, int fa) {
        int hashv = Hash[w[now]];
        xu[now] = ++cnt;
        int prehave = have[hashv];
        have[hashv]++;
        for (int i = 0; i < mp[now].size(); i++) {
            int ne = mp[now][i];
            if (ne == fa) continue;
            int pre = have[hashv];
            dfs(ne, now);
            if(pre<have[hashv]){
                c[1]++;
                c[xu[ne]]--;
                c[ed[ne] + 1]++;
            }
        }
        ed[now] = cnt;
        if(have[hashv]-prehave<total[hashv]){
            c[xu[now]]++;
            c[ed[now] + 1]--;
        }
    }
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> w[i];
            if (Hash[w[i]] == 0) Hash[w[i]] = ++num;
            total[Hash[w[i]]]++;
        }
        for (int i = 1; i < n; i++) {
            int x, y;
            cin >> x >> y;
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        dfs(1, 0);
        int res = 0;
        for (int i = 1; i <= n;i++){
            c[i] += c[i - 1];
            if (c[i] == 0) res++;
        }
        cout << res << endl;
        return 0;
    }
    
  • 相关阅读:
    论线段树:二
    BST 二叉搜索树
    论线段树:一
    [luoguP3627][APIO2009]抢掠计划
    二分图匹配(匈牙利算法)
    SPFA 全面讲解
    markdown的常用高级操作。
    UVA11235 Frequent values
    P2279 [HNOI2003]消防局的设立
    P2216 [HAOI2007]理想的正方形
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14287979.html
Copyright © 2011-2022 走看看