BZOJ1110: [POI2007]砝码Odw
Description
在byteotian公司搬家的时候,他们发现他们的大量的精密砝码的搬运是一件恼人的工作。公司有一些固定容量的容器可以装这些砝码。他们想装尽量多的砝码以便搬运,并且丢弃剩下的砝码。每个容器可以装的砝码数量有限制,但是他们能够装的总重量不能超过每个容器的限制。一个容器也可以不装任何东西。任何两个砝码都有一个特征,他们的中总有一个的重量是另外一个的整数倍,当然他们也可能相等。
Input
输入文件的第一行包含两个数n和m。表示容器的数量以及砝码的数量。(1<=n, m<=100000) 第二行包含n个整数wi,表示每个容器能够装的最大质量。(1<=wi<=1000000000) 第三行包含m个整数mj,表示每个砝码的质量。(1<=mj<=1000000000)
Output
输出文件要求仅包含一个数,为能够装进容器的最多的砝码数量。
Sample Input
2 4
13 9
4 12 2 4
13 9
4 12 2 4
Sample Output
3
因为我们要求放进的砝码数最多,所以我们肯定从按质量小到大放。
那么我们就可以排序后二分答案啦,转化成判断问题。
然后我们发现可以从最大的开始往前放,而且每次肯定要放在尽可能大的容器里,这用相邻交换法不难证明。
那么用一个堆来维护一下就好啦,时间复杂度O(Nlog^2N)。
时间好虚。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; int n,m,B[maxn],A[maxn]; priority_queue<int> Q; int check(int x) { while(Q.size()) Q.pop(); rep(i,1,n) Q.push(A[i]); dwn(i,x,1) { int v=Q.top();Q.pop(); if(v<B[i]) return 0; Q.push(v-B[i]); } return 1; } int main() { n=read();m=read(); rep(i,1,n) A[i]=read(); rep(i,1,m) B[i]=read(); sort(B+1,B+m+1); int l=0,r=m+1,mid; while(l+1<r) if(check(mid=l+r>>1)) l=mid; else r=mid; printf("%d\n",l); return 0; }