• BZOJ1237: [SCOI2008]配对


    感觉此题还是挺可做的...

    首先考虑最无脑的做法:

      我需要知道接下来要给谁配对,在另一个数组中还没有被选的有哪些,
      并记录已选的造成的贡献

    要想知道没选的有哪些的话,这直接记录问题就很大了,考虑能不能省去这一步

    那么无非是两个数组被选的集合的右端点同时往右扩张,
    或是每个数可与其配对的数的范围大概为一个常数

    直觉是这样的,考虑证明一下(其实我也不会证...)

    先把两个数组排序,
    这样对于一个 ai 来说他可选的一定是在 b 数组中的一段连续区间

    在注意到每个数组中元素不重复之后,可以发现

    显然特别极端的情况是不能可能的,比如

    这是显然可以随意调整一下的,最后最左边的点一定是选择一个离他较近的点的

    想证明其他的基本同理,试图枚举下面的点与上面的值是否相同即可

    然后大概感觉上就没什么问题了,四个的话也是可以枚举值是否相同做的

    好像就到 3 了,可以考虑 n = 3 且 a_i b_i 都相同的时候,
    显然是三个交叉选要优的,要么就无解了。。

    然后就粗糙的证完了,估计考场上也就这样了

    关于保证两两配对,状态定义为 f[i] 表示给前 i 个配好对之后的最小代价
    只要每次转移选完当前的从前边的状态转移过来就行


     代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 100005;
    
    int n;
    ll a[MAXN], b[MAXN], f[MAXN];
    
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%lld%lld", &a[i], &b[i]);
            f[i] = 200000000000000ll;
        }
        if(n == 1 && a[1] == b[1]) {
            puts("-1");
            return 0;
        }
        sort(a + 1, a + n + 1);
        sort(b + 1, b + n + 1);
        f[0] = 0ll;
        for(int i = 1; i <= n; ++i) {
            if(a[i] != b[i]) f[i] = f[i - 1] + abs(a[i] - b[i]);
            if(i >= 2 && a[i] != b[i - 1] && a[i - 1] != b[i]) f[i] = min(f[i], f[i - 2] + abs(a[i] - b[i - 1]) + abs(a[i - 1] - b[i]));
            if(i >= 3) {
                if((a[i] != b[i - 1]) && (a[i - 1] != b[i - 2]) && (a[i - 2] != b[i])) f[i] = min(f[i], f[i - 3] + abs(a[i] - b[i - 1]) + abs(a[i - 1] - b[i - 2]) + abs(a[i - 2] - b[i]));
                if((a[i] != b[i - 2]) && (a[i - 1] != b[i]) && (a[i - 2] != b[i - 1])) f[i] = min(f[i], f[i - 3] + abs(a[i] - b[i - 2]) + abs(a[i - 1] - b[i]) + abs(a[i - 2] - b[i - 1]));
            }
        }
        printf("%lld
    ", (f[n] == 200000000000000ll ? -1 : f[n]));
        return 0;
    }
    

      

    禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载 ,用户转载请注明出处:https://www.cnblogs.com/xcysblog/
  • 相关阅读:
    oracle常用hint的用法
    浅谈reverse函数与django哲学
    javascript console
    python os.path模块
    删除列表元素
    Python模块学习 pickle, cPickle 对象序列化/反序列化
    Python中zip()函数用法举例
    Python 字符串方法详解
    常用正则验证
    python中下划线的用法
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9726864.html
Copyright © 2020-2023  润新知