【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

 

posted @ 2017-10-21 16:43  BearChild  阅读(234)  评论(0编辑  收藏  举报