【Foreign】K优解 [堆]
K优解
Time Limit: 20 Sec Memory Limit: 512 MBDescription
给定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
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 个元素取为2 且 i + 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 }