zoukankan      html  css  js  c++  java
  • Codeforces Round #584

    传送门

    A. Paint the Numbers

    签到。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 105;
    int n;
    int a[N];
    bool used[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        sort(a + 1, a + n + 1);
        int ans = 0;
        for(int i = 1; i <= n; i++) {
            if(used[i]) continue;
            ++ans;
            for(int j = i; j <= n; j++) {
                if(a[j] % a[i] == 0) used[j] = 1;
            }
        }
        cout << ans;
        return 0;
    }
    

    B. Koala and Lights

    由于数据范围很小,暴力枚举即可。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 105;
     
    int n;
    int a[N], b[N];
    char s[N];
     
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n;
        cin >> s + 1;
        for(int i = 1; i <= n; i++) cin >> a[i] >> b[i];
        int ans = 0;
        for(int i = 1; i <= n; i++) {
            if(s[i] == '1') ++ans;
        }
        for(int i = 1; i <= 5000; i++) {
            int tmp = 0;
            for(int j = 1; j <= n; j++) {
                if(i - b[j] < 0) continue;
                int now = i - b[j];
                if(now % a[j] == 0) {
                    if(s[j] == '1') s[j] = '0';
                    else if(s[j] == '0') {
                        s[j] = '1';
                    }
                }
            }
            for(int j = 1; j <= n; j++) {
                if(s[j] == '1') ++tmp;
            }
    //        if(i < 10) cout << tmp << '
    ';
            ans = max(ans, tmp);
        }
        cout << ans;
        return 0;
    }
    

    C. Paint the Digits

    题意:
    给出一串数字,现在要给这串数字涂上两种颜色(1,2),要求涂色过后从前往后将(1)排开,再将(2)排开,最终得到一个非递减序列。

    思路:
    首先序列自动机预处理下一位,然后贪心处理即可。
    感性想一下很容易知道染色方案,对于当前位,(1)的颜色肯定是下一个最小的值,如果不是则不满足条件;(1)染完色过后按同样的方法对(2)进行染色,但是起点不同,注意处理一下。
    还有一个细节:(1)染的颜色的最大值不能超过前面没染颜色的最小值,否则也不满足条件。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 5;
     
    int T, n;
    char s[N];
    int nxt[N][26];
    int last[26];
    int col[N];
     
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> n;
            cin >> s + 1;
            for(int i = 1; i <= n; i++) col[i] = 0;
            for(int i = 0; i < 26; i++) last[i] = n + 1;
            for(int i = n; i >= 0; i--) {
                for(int j = 0; j < 26; j++) nxt[i][j] = last[j];
                if(i) last[s[i] - '0'] = i;
            }
            int start = 0, up = 26;
            for(int i = 0, k; i <= n; i = k) {
                int jump = 0;
                int low = (i == 0 ? 0 : s[i] - '0');
                for(int j = low; j < up; j++) {
                    if(nxt[i][j] <= n) {
                        k = nxt[i][j];
                        jump = 1;
                        break;
                    }
                }
                if(jump == 0) break;
                col[k] = 1;
                start = s[k] - '0';
                if(k != i + 1 && up == 26) {
                    up = s[i + 1] - '0' + 1;
                }
            }
            for(int i = 0, k; i <= n; i = k) {
                int jump = 0;
                int low = (i == 0 ? start : s[i] - '0');
                for(int j = low; j < 26; j++) {
                    if(nxt[i][j] <= n && !col[nxt[i][j]]) {
                        k = nxt[i][j];
                        jump = 1;
                        break;
                    }
                }
                if(!jump) break;
                col[k] = 2;
            }
            int ok = 1;
            for(int i = 1; i <= n; i++) {
                if(!col[i]) ok = 0;
            }
            if(!ok) cout << '-' << '
    ';
            else {
                for(int i = 1; i <= n; i++) cout << col[i];
                cout << '
    ';
            }
        }
        return 0;
    }
    

    D. Cow and Snacks

    全局视野来看,并查集搞搞就行,答案就与生成树有关。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 5;
     
    int n, k;
    int a[N], b[N];
    int f[N], sz[N];
     
    int find(int x) {
        return f[x] == x ? f[x] : f[x] = find(f[x]);
    }
     
    bool Union(int x, int y) {
        int fx = find(x), fy = find(y);
        if(fx != fy) {
            sz[fy] += sz[fx];
            f[fx] = fy;
            return true;
        }
        return false;
    }
     
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> k;
        for(int i = 1; i <= k; i++) {
            cin >> a[i] >> b[i];
        }
        for(int i = 1; i <= n; i++) f[i] = i, sz[i] = 1;
        int ans = 0;
        for(int i = 1; i <= k; i++) {
            if(!Union(a[i], b[i])) ++ans;
        }
    //    int cnt = 0;
    //    for(int i = 1; i <= n; i++) {
    //        if(find(i) == i) {
    //            cnt += sz[i] - 1;
    //            cout << sz[i] << '
    ';
    //        }
    //    }
    //    int ans = n - cnt;
        cout << ans;
        return 0;
    }
    

    E. Rotate Columns

    题意:
    给出一个(n*m)的矩形,满足(nleq 12,mleq 2000),现在你可以对任意一列执行任意次滑动操作。
    (r_i)为第(i)行的最大值,求(sum_{i=1}^nr_i)最大为多少。

    思路:
    一开始看作行也可以滑动,然后就写了一个假题= =

    • 有一个很重要的观察,就是最后的最大值只与最大值最大的(n)列有关。
    • 为什么?
    • 假设现在第(i)列的最大值为第(n+1)大,那么在最优方案中,它肯定不能成为最大值,因为总会存在一列(j)可以令其滑动到(i)的位置并且其最大值大于(j)列。
    • 那么我们将最大的(n)列拿出来随机就行了。
    • 因为数据很小,所以可以考虑状压。
    • 枚举状态(s),表示在之前的(i-1)列中选取某些行作为最大值,和的最大值。之后会新加进来第(i)列,显然,第(i)列行的状态只能为(((1<<n)-1) xor s)的子集。之后枚举循环位移更新即可。
    • 直接枚举循环位移时间复杂度可能会多处一个(O(n)),那么可以将这部分预处理一下。

    一开始我卡在枚举循环位移这里,后面想了下,只有枚举循环位移,才会覆盖到所有情况。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define INF 0x3f3f3f3f
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    //#define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 12, M = 2000;
     
    int n, m;
    int a[N][M];
    pii b[M];
     
    void run() {
        cin >> n >> m;
        vector <int> col(m);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> a[i][j];
                col[j] = max(col[j], a[i][j]);
            }
        }
        for (int i = 0; i < m; i++) b[i] = MP(col[i], i);
        sort(b, b + m); reverse(b, b + m);
        m = min(m, n);
        int lim = 1 << n;
        vector <vector<int>> w(m, vector<int>(lim));
        for (int i = 0; i < m; i++) {
            int j = b[i].se;
            for (int s = 0; s < lim; s++) {
                for (int k = 0; k < n; k++) {
                    int sum = 0;
                    for (int p = 0; p < n; p++) {
                        if (s >> ((p + k) % n) & 1) {
                            sum += a[p][j];
                        }
                    }
                    w[i][s] = max(w[i][s], sum);
                }
            }
        }
        vector <int> dp(lim);
        for (int i = 0; i < m; i++) {
            vector <int> new_dp(lim);
            for (int s = 0; s < lim; s++) {
                int other = (lim - 1) ^ s;
                for (int sub = other; ; sub = (sub - 1) & other) {
                    int Max = w[i][sub];
                    new_dp[s ^ sub] = max(new_dp[s ^ sub], dp[s] + Max);
                    if (sub == 0) break;
                }
            }
            swap(dp, new_dp);
        }
        cout << dp[lim - 1] << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        int t; cin >> t;
        while(t--) run();
        return 0;
    }
    

    F. Koala and Notebook

    题意:
    给出一张(n)个点(m)条边的无向图,每条边的编号依次为(1,2,cdots,m)
    现在从(1)号结点出发,每经过一条边,则在目前答案后面连上当前边的编号。
    比如(1->2),编号为(10),到达(2)结点的结果就为(10);之后(2->3)的编号为(11),那么结果就为(1011)
    现在要求到达每个节点的最小答案,由于这个答案可能很大,所以输出对(1e9+7)取模的答案。

    思路:
    一开始想不是很好想,因为思考起来还是挺麻烦的,比较大小则要考虑很多东西。
    但其实细化一下思路就能清晰一点:

    • 一般比较字典序大小,第一看长度,第二看不同位的大小关系。
    • 但这里长度不是很好比较,不同编号可能有不同的长度。怎么处理?
    • 拆边就行!将编号拆成多个一位,这样长度就很好考虑。
    • 接下来考虑大小关系。
    • 因为我们从(1)出发,所以可以跑个(bfs),每次往小的边优先走,那么既能保证长度最小,也能保证值最小了。

    大概思路就是这样,关键点就是拆边。
    但代码实现还有一点细节:我们(bfs)时用(vector)来模拟队列,之后再将距离拆细一点(即并不是距离离起点相同的点都拿出来更新),这样就能保证每次更新得到的都是最小答案。不然对于(0)通过(1)去更新其它点,还不如(1)通过(0)去更新其它点优,就有问题。
    说这么多废话,代码看起来还是比较好懂:

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    //#define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 1e6 + 5, MOD = 1e9 + 7;
     
    int n, m;
    vector <int> g[N][10];
    bool chk[N];
    int ans[N];
     
    void run() {
        int np = n;
        for(int i = 1; i <= m; i++) {
            int u, v; cin >> u >> v;
            int t = i;
            vector <int> e;
            while(t) {
                e.push_back(t % 10);
                t /= 10;
            }
            reverse(all(e));
            int pre = u;
            for(int j = 0; j < sz(e); j++) {
                int to = (j == sz(e) - 1 ? v : ++np);
                g[pre][e[j]].push_back(to);
                pre = to;
            }
            pre = v;
            for(int j = 0; j < sz(e); j++) {
                int to = (j == sz(e) - 1 ? u : ++np);
                g[pre][e[j]].push_back(to);
                pre = to;
            }
        }
        vector <vector<int>> q(np + 1);
        chk[1] = 1; q[0].push_back(1);
        int T = 0;
        for(int i = 0; i <= T; i++) {
            for(int j = 0; j < 10; j++) {
                int f = 0;
                for(auto x : q[i]) {
                    for(auto it : g[x][j]) {
                        if(!chk[it]) {
                            chk[it] = 1; f = 1;
                            ans[it] = (1ll * 10 * ans[x] % MOD + j) % MOD;
                            q[T + 1].push_back(it);
                        }
                    }
                }
                if(f) ++T;
            }
        }
        for(int i = 2; i <= n; i++) cout << ans[i] << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        while(cin >> n >> m) run();
        return 0;
    }
    

    G1. Into Blocks (easy version)

    题意:
    给出一个长度为(n,nleq 2e5)的序列。
    现在可以执行操作:将全部的(x)变为(y)
    现在问最少多少次操作,使得所有值相同的元素都在同一块中。

    思路:

    • 考虑最终状态,一定为多个整块,并且在一个整块中,一定是多个颜色都变为同一颜色。
    • 那么对于(1)位置的颜色,一定最后也在一块中,并且目前块结尾为(last[a_1]);同时,中间的所有元素都会变为同一颜色,那么我们直接扫过去,因为可能(last[a_i]>last[a_1]),我们直接更新右边界即可。
    • 最后我们划分出了多个大区间,在每个区间中贪心考虑保留个数最多的颜色即可。那么我们划分时用一个桶维护一下权值数量即可。

    详见代码:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 200005;
     
    int n, q;
    int a[N];
    int fir[N], last[N];
    int cnt[N];
     
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> q;
        for(int i = 1; i <= n; i++) cin >> a[i];
        for(int i = 1; i <= n; i++) {
            if(fir[a[i]] == 0) fir[a[i]] = i;
        }
        for(int i = n; i >= 1; i--) {
            if(last[a[i]] == 0) last[a[i]] = i;
        }
        int ans = 0;
        for(int i = 1, j; i <= n; i = j + 1) {
            j = last[a[i]];
            int st = i;
            while(i < j) {
                ++i; j = max(last[a[i]], j);
            }
            int tmp = 0;
            for(int k = st; k <= j; k++) {
                if(++cnt[a[k]] > tmp) tmp = cnt[a[k]];
            }
            ans += j - st + 1 - tmp;
        }
        cout << ans;
        return 0;
    }
    
  • 相关阅读:
    IDEA如何打包可运行jar的一个问题。
    从一个脚本谈loadrunner的脚本初始化
    explain 用法详解
    linux zip 命令详解
    Jmeter使用——参数化
    Jmeter Constant Throughput Timer 使用
    产生随机时间的例子
    Mysql的列索引和多列索引(联合索引)
    Loadrunner负载机agent
    Spring context:property-placeholder 一些坑
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11530955.html
Copyright © 2011-2022 走看看