• 【Foreign】K优解 [堆]


    K优解

    Time Limit: 20 Sec  Memory Limit: 512 MB

    Description

      给定n个行数,每行m个。在每行中选出一个数来,求出前 k 小的异或和。

    Input

      第一行 3 个正整数 n,m,k。
      接下来 n 行,每行 m 个非负整数,第 i 行第 j 个为权值a[i][j]。

    Output

      一行一个数表示答案。

    Sample Input

      3 2 2
      11 21
      9 25
      17 19

    Sample Output

      2

    HINT

      n*m<=300000,k<=300000,保证m^n>=k,a[i][j]均不超过10^9

    Solution

      先对于每个 i,将每行的 a[i][1]~a[i][m] 从小到大排序,再将按照其元素差值多关键字排序(共m-1个关键字)。

      那么我们知道,最小的方案肯定是所有行都取第一个。由于其有一些特殊,我们先抛开这个方案。
      我们知道,次小的方案是(2,1,1,1…),把这个状态加入,由较优方案扩展较劣方案,对于每一个状态,我们记录其扩展到第几行,以及取第几个元素

      在已经得到前 k 优的方案时,当前所有方案中还未扩展的最好的方案x(其最后扩展位置为 i),就是第 k+1 优

      从方案x,我们可以扩展出几个较劣解

        1、x 的第 i 个元素不取m:将 i 行取的元素增加1(扩展位置为 i

        2、i + 1 <= n:将 i+1 行取为2(扩展位置为 i+1

        3、x 的第 i 个元素取为2i + 1 <= n:将 i 行取为1,i+1 行取为2(扩展位置为 i+1

      由此,每个解都可由唯一的优于它的解扩展得来。

      用个维护一下,每次取出最小的即可。

    Code

     1 #include<iostream>
     2 #include<string>
     3 #include<algorithm>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cmath>
     8 #include<vector>
     9 #include<queue>
    10 using namespace std;
    11 typedef long long s64;
    12 
    13 const int ONE = 300005;
    14 const int MOD = 1e9 + 7;
    15 
    16 int n, m, k;
    17 vector <int> A[ONE];
    18 int id[ONE];
    19 s64 Ans;
    20 
    21 struct power
    22 {
    23         s64 val;
    24         int pt, id;
    25         bool operator <(power a) const
    26         {
    27             return a.val < val;
    28         }
    29 };
    30 priority_queue <power> q;
    31 
    32 int cmp(int a, int b)
    33 {
    34         for(int i = 1; i < m; i++)
    35         {
    36             if(A[a][i + 1] - A[a][i] < A[b][i + 1] - A[b][i]) return 1;
    37             if(A[a][i + 1] - A[a][i] > A[b][i + 1] - A[b][i]) return 0;
    38         }
    39         return 0;
    40 }
    41 
    42 int get()
    43 {
    44         int res=1,Q=1;  char c;
    45         while( (c=getchar())<48 || c>57)
    46         if(c=='-')Q=-1;
    47         if(Q) res=c-48; 
    48         while((c=getchar())>=48 && c<=57) 
    49         res=res*10+c-48;
    50         return res*Q; 
    51 }
    52 
    53 int main()
    54 {
    55         n = get();    m = get();    k = get();
    56         for(int i = 1; i <= n; i++)
    57         {
    58             A[i].push_back(0);
    59             for(int j = 1; j <= m; j++)
    60                 A[i].push_back(get());
    61             sort(A[i].begin(), A[i].end());
    62             id[i] = i;
    63         }
    64 
    65         sort(id + 1, id + n + 1, cmp);
    66 
    67         s64 res = 0;
    68         for(int i = 1; i <= n; i++) res += A[i][1];
    69         Ans = res;
    70 
    71         q.push((power){res - A[id[1]][1] + A[id[1]][2], 1, 2});
    72 
    73         for(int i = 2; i <= k; i++)
    74         {
    75             power u = q.top(); q.pop();
    76             Ans ^= u.val;
    77 
    78             if(u.id + 1 <= m)
    79                 q.push((power){u.val - A[id[u.pt]][u.id] + A[id[u.pt]][u.id + 1], u.pt, u.id + 1});
    80             if(u.pt + 1 <= n && 2 <= m)
    81                 q.push((power){u.val - A[id[u.pt + 1]][1] + A[id[u.pt + 1]][2], u.pt + 1, 2});
    82             if(u.pt + 1 <= n && u.id == 2)
    83                 q.push((power){u.val - A[id[u.pt]][2] + A[id[u.pt]][1] - A[id[u.pt + 1]][1] + A[id[u.pt + 1]][2], u.pt + 1, 2});
    84         }
    85 
    86         printf("%lld", Ans);
    87 }
    View Code
  • 相关阅读:
    int和Integer有什么区别
    互联网思维的四个核心观点九大思维解读
    未来流行的12种商业模式
    小黑裙三级分销模式
    数据库设计三大范式
    数据库设计中常见表结构的设计技巧
    软件架构的演进,了解单体架构,垂直架构,SOA架构和微服务架构的变化历程
    查理芒格的25种人类误判心理学
    聪明的老板,都懂得让人占便宜(经典)
    真正聪明的人,从不占人便宜
  • 原文地址:https://www.cnblogs.com/BearChild/p/7705165.html
Copyright © 2020-2023  润新知