• C. Garland (贪心 || DP)


    传送门

    题意: 一行有 n 个数字,是 1 ~ n 的一个排列, 现在, 给你 n 个数, 0 代表这个数还没有填好。 然后,现在定义这 n 个数的复杂度是 相邻两个数的奇偶性不同的组数。

        例如, 5 1 2 3 4 这一个排列的复杂度是 (1,2),(2,3),(3,4) =  3; 现在问你把那些 0 填上数字,最低的复杂度是多少。

    解: 有两种做法。

      一、贪心(比较复杂)

      对每段连续的0,维护一个 l, r,  num; 代表 这段连续的 0 左边第一个非0的数的奇偶性,若,左边没有非0数,则 l = -1; r 同理。

      num则代表0的个数。  然后, 对于所有的连续的0,按照num从小到大排序,优先,填那些 num 较小的且 左右端点奇偶性相等的段。

      因为,奇偶性相等的,若你不填它,它会产生2的贡献。 而,左右端点奇偶性不同的,无论你怎么填,它都是1的贡献。

      但是,对于 l = -1 和 r = -1 这种情况的,你填满它可以减少1的贡献,你不填则产生1的贡献。  所以, 优先填奇偶性相等的,因为填满可以减少2的贡献。

      然后,再考虑 l = -1 和 r = -1 的情况。 即可。

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int a[N];
    
    struct note {
        int l, r, num;
        bool flag;
        note(int l, int r, int num) : l(l), r(r), num(num) { flag = false; }
        bool operator < (const note& a) const {
            return num < a.num;
        }
    };
    
    vector<note> Q;
    
    int main() {
    
        int n; scanf("%d", &n);
        int ans = 0;
        int ji = n / 2, ou = n / 2;
        if(n & 1) ji++;
        a[0] = -1; a[n + 1] = -1;
        rep(i, 1, n) {
            scanf("%d", &a[i]);
            if(a[i - 1] > 0 && a[i] > 0) ans += (a[i - 1] & 1) ^ (a[i] & 1);
            if(a[i]) {
                if(a[i] & 1) ji--;
                else ou--;
            }
        }
        if(n == 1) return puts("0"),0;
        if(ji == (n + 1) / 2 && ou == n / 2) return puts("1"),0;
        rep(i, 1, n) {
            if(a[i] == 0) {
                int st = i;
                while(i <= n && !a[i]) i++;
                int l, r;
                if(a[st - 1] == -1) l = -1;
                else l = a[st - 1] & 1;
                if(a[i] == -1) r = -1;
                else r = a[i] & 1;
                Q.pb(note(l, r, i - st));
            }
        }
        sort(Q.begin(), Q.end());
        for(int i = 0; i < Q.size(); i++) {
            if(Q[i].l == Q[i].r) {
                if(Q[i].l) {
                    if(ji >= Q[i].num) {
                        Q[i].flag = true;
                        ji -= Q[i].num;
                    }
                }
                else {
                    if(ou >= Q[i].num) {
                        Q[i].flag = true;
                        ou -= Q[i].num;
                    }
                }
            }
        }
        for(int i = 0; i < Q.size(); i++) {
            if(Q[i].l == -1 || Q[i].r == -1) {
                int ch;
                if(Q[i].l != -1) ch = Q[i].l;
                else ch = Q[i].r;
                if(ch) {
                    if(ji >= Q[i].num) {
                        ji -= Q[i].num;
                        Q[i].flag = true;
                    }
                }
                else {
                    if(ou >= Q[i].num) {
                        ou -= Q[i].num;
                        Q[i].flag = true;
                    }
                }
            }
        }
        for(int i = 0; i < Q.size(); i++) {
            if(!Q[i].flag) {
                if(Q[i].l == Q[i].r) ans += 2;
                else ans++;
            }
        }
        printf("%d
    ", ans);
        return 0;
    }
    View Code

      二、DP 

      4维dp, dp[ i ][ j ][ k ][ op ] : 1 ~ i 的 0 填了 j 个奇数, k 个偶数, 第 i 个数是 op 的最低复杂度。 op = 1 代表奇数, op = 0代表 偶数。 

      然后 j + k 必须 小于等于 1 ~ i 中 0 的个数 now0 才能转移。  然后分成 a[ i ] != 0 和 a[ i ] = 0 两种情况。

      a[ i ] 不等于0,则根据 a[ i ] 的奇偶性直接从前面转移过来就行了。 

      a[ i ] 等于0, 则又分为a[ i ] 是奇数, a[ i ] 是偶数两种情况。

      

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f
    #define inf LLONG_MAX
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int a[N];
    
    int dp[101][101][101][2];
    
    int main() {
    
        int n; scanf("%d", &n);
        int ans = 0;
        int ji = n / 2, ou = n / 2;
        if(n & 1) ji++;
        rep(i, 1, n) {
            scanf("%d", &a[i]);
            if(a[i]) {
                if(a[i] & 1) ji--;
                else ou--;
            }
        }
        if(n == 1) return puts("0"),0;
        if(ji == (n + 1) / 2 && ou == n / 2) return puts("1"),0;
        mem(dp, INF);
        dp[0][0][0][0] = dp[0][0][0][1] = 0;
        int now0 = 0;
        rep(i, 1, n) {
            if(!a[i]) now0++;
            rep(j, 0, ou) {
                rep(k, 0, ji) {
                    if(j + k <= now0) {
                        if(a[i] > 0) {
                            if(a[i] & 1) dp[i][j][k][1] = min(dp[i - 1][j][k][0] + 1, dp[i - 1][j][k][1]);
                            else dp[i][j][k][0] = min(dp[i - 1][j][k][0], dp[i - 1][j][k][1] + 1);
                        }
                        else {
                            dp[i][j][k][0] = min(dp[i - 1][j - 1][k][0], dp[i - 1][j - 1][k][1] + 1);
                            dp[i][j][k][1] = min(dp[i - 1][j][k - 1][0] + 1, dp[i - 1][j][k - 1][1]);
                        }
                    }
                }
            }
        }
        printf("%d
    ", min(dp[n][ou][ji][0], dp[n][ou][ji][1]));
        return 0;
    }
    View Code
    一步一步,永不停息
  • 相关阅读:
    【转载】make: Nothing to be done for `all'. 解决方法
    P4行为模型BMV2安装
    P4行为模型BMV2依赖关系安装:thrift nanomsg nnpy安装
    P4factory ReadMe 剩余部分
    P4factory ReadMe Quickstart 安装p4factory
    Git 使用ssh密钥
    c++ 有swap函数
    c++ 引用
    topk两种解法
    xgboost和gbdt区别
  • 原文地址:https://www.cnblogs.com/Willems/p/12200089.html
Copyright © 2020-2023  润新知