problem sort
题目大意
有n个数组,每个数组有a[i]个元素,每次可以将至多k个数组合并为一个数组,所花费代价为这些数组的元素和。给定代价上限,求将所有数组合并为1个数组的最小k。
解题分析
二分k后就成了k叉哈夫曼树问题。
对于k叉哈夫曼树,可以利用所合并元素的权值单调性,用两个双端队列来实现。
另外,如果(n-1)%(k-1) != 0 , 则需要另外在补上(k-1) - (n-1)%(k-1)个0。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 100008 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 32 int T; 33 int n,limit; 34 int a[N*10],b[N*10],c[N*10]; 35 36 int check(int k) 37 { 38 //printf("%d ",k ); 39 int tmp=((k-1)-(n-1) % (k-1)) % (k-1); 40 int m=n+tmp; 41 rep(i,1,tmp) b[i]=0; 42 rep(i,tmp+1,m) b[i]=a[i-tmp]; 43 LL s=0; 44 int i=1,l=1,r=0,op=0,sum=0; 45 while (i<=m) 46 { 47 if (l>r || b[i]<=c[l]) 48 { 49 op++; 50 sum+=b[i]; 51 i++; 52 } 53 else 54 { 55 op++; 56 sum+=c[l]; 57 l++; 58 } 59 if (op==k) 60 { 61 s+=sum; 62 c[++r]=sum; 63 op=sum=0; 64 } 65 } 66 while (l<=r) 67 { 68 op++; 69 sum+=c[l]; 70 l++; 71 if (op==k) 72 { 73 s+=sum; 74 c[++r]=sum; 75 op=sum=0; 76 } 77 } 78 //rep(i,1,m) printf("%d ",b[i]); printf(" "); 79 //rep(i,1,r) printf("%d ",c[i]); printf(" "); 80 if (op!=1) s+=sum; 81 //printf("%lld ",s ); 82 return s<=limit; 83 } 84 85 int cmp(int x,int y) 86 { 87 return x>y; 88 } 89 int main() 90 { 91 scanf("%d",&T); 92 while (T--) 93 { 94 scanf("%d%d",&n,&limit); 95 rep(i,1,n) scanf("%d",&a[i]); 96 sort(a+1,a+n+1); 97 int l=2,r=n,mid,res; 98 while (l<=r) 99 { 100 mid=(l+r)/2; 101 if (check(mid)) 102 { 103 res=mid; 104 r=mid-1; 105 } 106 else l=mid+1; 107 } 108 printf("%d ",res); 109 } 110 }