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

    https://codeforces.com/contest/1287/

    A - Angry Students

    题意:求A后面的P最长连续有几个?

    题解:?

    int n;
    char s[200005];
    
    void test_case() {
        scanf("%d%s", &n, s + 1);
        int cnt = 0, ans = 0;
        int b = 1;
        while(b <= n && s[b] == 'P')
            ++b;
        for(int i = b; i <= n; ++i) {
            if(s[i] == 'P')
                ++cnt;
            else {
                ans = max(ans, cnt);
                cnt = 0;
            }
        }
        ans = max(ans, cnt);
        printf("%d
    ", ans);
    }
    

    一种不需要判断结尾的思路是,一边统计cnt,一边尝试更新ans。

    B - Hyperset

    题意:每个属性只有3种值。定义三张牌是一个SET,当他们每个属性要么全等要么两两不同。

    题解:枚举两张牌,可以确定第三张牌。

    注:原来没有重复的牌的啊,这个constraint完全没必要啊,把这题变成一个送分题了。

    struct TrieNode {
        int data;
        int nxt[3];
     
        void Init() {
            data = 0;
            memset(nxt, 0, sizeof(nxt));
        }
    };
     
    struct Trie {
        static const int MAXN = 45000;
        TrieNode tn[MAXN + 5];
        int root, top;
     
        int NewNode() {
            tn[++top].Init();
            return top;
        }
     
        void Init() {
            top = 0;
            root = NewNode();
        }
     
        void Insert(int *a, int len, int data) {
            int cur = root;
            for(int i = 1; i <= len; ++i) {
                int &nxt = tn[cur].nxt[a[i]];
                if(!nxt)
                    nxt = NewNode();
                cur = nxt;
            }
            tn[cur].data += data;
        }
     
        int Query(int *a, int len) {
            int cur = root;
            for(int i = 1; i <= len; ++i) {
                int &nxt = tn[cur].nxt[a[i]];
                if(!nxt)
                    return 0;
                cur = nxt;
            }
            return tn[cur].data;
        }
    } trie;
     
    int n, k;
    char s[35];
    int st[128], t[1505][35], r[35];
     
    void test_case() {
        st['S'] = 0;
        st['E'] = 1;
        st['T'] = 2;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i) {
            scanf("%s", s + 1);
            for(int j = 1; j <= k; ++j)
                t[i][j] = st[s[j]];
            trie.Insert(t[i], k, 1);
        }
        ll sum = 0;
        for(int i1 = 1; i1 <= n; ++i1) {
            for(int i2 = i1 + 1; i2 <= n; ++i2) {
                int ty = 1;
                for(int j = 1; j <= k; ++j) {
                    r[j] = (3 - (t[i1][j] + t[i2][j]) % 3) % 3;
                    if(r[j] != t[i1][j])
                        ty = 0;
                }
                if(ty == 0)
                    sum += trie.Query(r, k);
                else
                    sum += trie.Query(r, k) - 2;
            }
        }
        printf("%lld
    ", sum / 3);
    }
    
    map<ll, int> M;
     
    int n, k;
    char s[35];
    int st[128], t[1505][35];
    ll val[1505];
     
    void test_case() {
        st['S'] = 0;
        st['E'] = 1;
        st['T'] = 2;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i) {
            scanf("%s", s + 1);
            ll r = 0;
            for(int j = 1; j <= k; ++j) {
                t[i][j] = st[s[j]];
                r = 3 * r + t[i][j];
            }
            M[r]++;
            val[i] = r;
        }
        ll sum = 0;
        for(int i1 = 1; i1 <= n; ++i1) {
            for(int i2 = i1 + 1; i2 <= n; ++i2) {
                ll r = 0;
                for(int j = 1; j <= k; ++j) {
                    int tmp = (3 - (t[i1][j] + t[i2][j]) % 3) % 3;
                    r = 3ll * r + tmp;
                }
                auto it = M.find(r);
                if(it != M.end()) {
                    if(r != val[i1])
                        sum += it->second;
                    else
                        sum += (it->second) - 2;
                }
            }
        }
        printf("%lld
    ", sum / 3);
    }
    
    unordered_map<ll, int> M;
    
    int n, k;
    char s[35];
    int st[128], t[1505][35];
    ll val[1505];
    
    void test_case() {
        M.reserve(3000);
        st['S'] = 0;
        st['E'] = 1;
        st['T'] = 2;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i) {
            scanf("%s", s + 1);
            ll r = 0;
            for(int j = 1; j <= k; ++j) {
                t[i][j] = st[s[j]];
                r = 3 * r + t[i][j];
            }
            M[r]++;
            val[i] = r;
        }
        ll sum = 0;
        for(int i1 = 1; i1 <= n; ++i1) {
            for(int i2 = i1 + 1; i2 <= n; ++i2) {
                ll r = 0;
                for(int j = 1; j <= k; ++j) {
                    int tmp = (3 - (t[i1][j] + t[i2][j]) % 3) % 3;
                    r = 3ll * r + tmp;
                }
                auto it = M.find(r);
                if(it != M.end()) {
                    if(r != val[i1])
                        sum += it->second;
                    else
                        sum += (it->second) - 2;
                }
            }
        }
        printf("%lld
    ", sum / 3);
    }
    

    Trie最快,但是一开始开太紧空间WA了一发。事实上真的没必要省空间,有多大开多大。

    C - Garland

    这个怎么贪心的啊?得看看别人怎么搞。

    题意:给一列数字,是一个自然数的排列,假如是0表示待填。填上这个序列使得复杂度最小。每个相邻的奇偶对贡献1复杂度。

    题解:dp,由于奇数之间是等价的,偶数之间也是等价的,每种填法对后面的影响也是只有最后一位数字。设dp[i][j][0/1]为前i个位置填了j个奇数,并且最后一位的奇偶性为0/1的最小复杂度。

    int a[105];
    int dp[105][105][2];
     
    void test_case() {
        int n;
        scanf("%d", &n);
        int cnt1 = (n + 1) / 2;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            if(a[i]) {
                if(a[i] & 1)
                    --cnt1;
            }
        }
        memset(dp, INF, sizeof(dp));
        dp[0][0][0] = 0;
        dp[0][0][1] = 0;
        for(int i = 1; i <= n; ++i) {
            if(a[i]) {
                int t = a[i] & 1;
                for(int j = 0; j <= cnt1; ++j) {
                    dp[i][j][t] = dp[i - 1][j][t];
                    dp[i][j][t] = min(dp[i][j][t], dp[i - 1][j][1 - t] + 1);
                }
            } else {
                for(int j = 1; j <= cnt1; ++j) {
                    dp[i][j][1] = dp[i - 1][j - 1][1];
                    dp[i][j][1] = min(dp[i][j][1], dp[i - 1][j - 1][0] + 1);
                }
                for(int j = 0; j <= cnt1; ++j) {
                    dp[i][j][0] = dp[i - 1][j][1] + 1;
                    dp[i][j][0] = min(dp[i][j][0], dp[i - 1][j][0]);
                }
            }
            /*for(int j = 0; j <= cnt1; ++j) {
                for(int t = 0; t <= 1; ++t)
                    printf("dp[%d][%d][%d]=%d
    ", i, j, t, dp[i][j][t]);
            }
            puts("");*/
        }
        printf("%d
    ", min(dp[n][cnt1][0], dp[n][cnt1][1]));
    }
    
    int a[105];
    int dp[105][105][2];
    
    void test_case() {
        int n, c;
        scanf("%d", &n);
        c = (n + 1) / 2;
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
    
        memset(dp, INF, sizeof(dp));
        dp[0][0][0] = 0;
        dp[0][0][1] = 0;
        for(int i = 1; i <= n; ++i) {
            if(a[i]) {
                int t = a[i] & 1;
                for(int j = 0; j <= c; ++j) {
                    dp[i][j + t][t] = dp[i - 1][j][t];
                    dp[i][j + t][t] = min(dp[i][j + t][t], dp[i - 1][j][1 - t] + 1);
                }
            } else {
                for(int j = 1; j <= c; ++j) {
                    dp[i][j][1] = dp[i - 1][j - 1][1];
                    dp[i][j][1] = min(dp[i][j][1], dp[i - 1][j - 1][0] + 1);
                }
                for(int j = 0; j <= c; ++j) {
                    dp[i][j][0] = dp[i - 1][j][1] + 1;
                    dp[i][j][0] = min(dp[i][j][0], dp[i - 1][j][0]);
                }
            }
            /*for(int j = 0; j <= cnt1; ++j) {
                for(int t = 0; t <= 1; ++t)
                    printf("dp[%d][%d][%d]=%d
    ", i, j, t, dp[i][j][t]);
            }
            puts("");*/
        }
        printf("%d
    ", min(dp[n][c][0], dp[n][c][1]));
    }
    

    贪心的解法复杂度低一个层次。

    D - Numbers on Tree

    题意:给一棵n<=2000的有根树,规定每个数的子树中有多少个节点的val比根节点的严格小。给这棵树填上任意一种合法的val(每个值都在[1,10^9]且满足上一句话)或报告不存在。

    题解:树的这类问题可能都是先往递归的方向考虑,假如是叶子,不用多说之间返回1,否则是中间节点。假如中间节点只有一棵子树,而且子树中的值是相异的,那么随便插进去然后把后面的数往后面挤,得到的也还是值全部相异的树。否则至少有两棵子树,假如他们的值也都是相异的也可以仿照上面解决,可惜搞不得,有可能不存在一个位置刚好满足要求。

    1. 这时候很显然的子树之间是没有关系的,可以给一棵子树的值整体提高一个水平,使得得到的值也是相异的,最简单的是加上上一棵子树的最大值(而不一定是size,假如没有进行算不并列的排名的话)。

    2. 事实上并不一定需要同一棵子树占据同一段连续的位置,直接全部混在一起算不并列的排名也可以。

    int n, root;
    
    int c[2005];
    
    vector<int> G[2005];
    vector<pii> vec[2005];
    
    void dfs(int u) {
        for(auto &v : G[u]) {
            dfs(v);
            for(auto &j : vec[v])
                vec[u].push_back(j);
        }
        if(c[u] > vec[u].size()) {
            puts("NO");
            exit(0);
        }
        sort(vec[u].begin(), vec[u].end());
        for(int i = 0; i < vec[u].size(); ++i)
            vec[u][i].first = i + 1;
        vec[u].insert(vec[u].begin() + c[u], {c[u] + 1, u});
        for(int i = c[u] + 1; i < vec[u].size(); ++i)
            ++vec[u][i].first;
    }
    
    void test_case() {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            int p;
            scanf("%d%d", &p, &c[i]);
            if(p)
                G[p].push_back(i);
            else
                root = i;
        }
        dfs(root);
        for(auto &j : vec[root])
            swap(j.first, j.second);
        sort(vec[root].begin(), vec[root].end());
        puts("YES");
        for(auto &j : vec[root])
            printf("%d ", j.second);
        puts("");
    }
    

    注意vector中insert是一个迭代器,而且确实可以在 for auto 中进行交换(应该在遍历中不会改变其他元素的操作都可以吧?)

  • 相关阅读:
    hdu_2224_The shortest path(dp)
    hdu_4824_Disk Schedule(dp)
    hdu_5680_zxa and set(想法题)
    hdu_5683_zxa and xor(非正解的暴力)
    hdu_1429_胜利大逃亡(续)(BFS状压)
    hdu_1254_推箱子(双BFS)
    hdu_1969_pie(二分)
    hdu_2446_Shell Pyramid(数学,二分)
    hdu_2141_Can you find it?(二分)
    5.2 nc + JMX查看分布式程序数据
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12155681.html
Copyright © 2011-2022 走看看