1. 程式人生 > >【Foreign】K優解 [堆]

【Foreign】K優解 [堆]

turn logs 異或 str src 得到 元素 code col

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

【Foreign】K優解 [堆]