题目描述
在暑假期间,校园里居住的学生较少,因此这是为代尔夫特理工大学图书馆增添新书的绝佳时机。这些新书的宽度都相同,但高度各不相同。由于现有的书架都已满,图书馆管理委员会决定新增一个书架来展示这些新书。

新书架有若干层,每层高度不同。每层最多可放 x x x 本书。由于可能会有剩余空间,管理委员会还希望在书架上展示一些艺术品,每层最多放一个艺术品。只有当该层旁边最多有 y y y 本书时,艺术品才能放下,因为艺术品占据与 x − y x-y x−y 本书相同的空间。例如,图 L.1 展示了一个书架,其中有三层可以放置艺术品。

管理委员会希望你找出,在能够放下所有新书的前提下,最多能在多少层上放置艺术品。
输入格式
输入包括:
- 一行四个整数 n n n、 m m m、 x x x、 y y y( 1 ≤ n , m ≤ 10 5 1 \leq n, m \leq 10^5 1≤n,m≤105, 1 ≤ y < x ≤ 1000 1 \leq y < x \leq 1000 1≤y<x≤1000),分别表示书架的层数、新书的数量、每层最多可放的书本数、每层与艺术品并排时最多可放的书本数。
- 一行 n n n 个整数 a a a( 1 ≤ a ≤ 10 9 1 \leq a \leq 10^9 1≤a≤109),表示每层的高度。
- 一行 m m m 个整数 b b b( 1 ≤ b ≤ 10 9 1 \leq b \leq 10^9 1≤b≤109),表示每本书的高度。
输出格式
如果能将 m m m 本书全部放入 n n n 层书架中,输出最多能放置的艺术品数量。否则,输出" impossible \texttt{impossible} impossible"。
输入输出样例 #1
输入 #1
4 8 4 2
4 8 6 2
1 2 3 5 7 7 8 8
输出 #1
3
输入输出样例 #2
输入 #2
4 11 3 2
2 2 2 2
1 1 1 1 1 1 1 1 1 1 1
输出 #2
1
输入输出样例 #3
输入 #3
2 10 3 2
8 6
4 2 1 3 6 2 1 3 4 5
输出 #3
impossible
输入输出样例 #4
输入 #4
3 8 8 3
7 9 4
2 3 4 5 6 7 8 9
输出 #4
3
题意
现在有 n n n 层书架,每层最多可放 x x x 本书,又有 m m m 本新书要放进书架里,且在放书时放的书的高度不得超过该层书架高度。
同时我们希望能放更多艺术品,每层最多放 1 1 1 个艺术品,且只有当该层旁边最多有 y y y 本书时,艺术品才能放下。
求在能够放下所有新书的前提下,最多能放多少艺术品,若新书都无法放完,则输出 impossible。
思路
因为求的是放的艺术品数,所以可以用二分来求艺术品数(因为若放 k k k 个艺术品可行,那么放更少的留的空间还会更大,一样可行,满足二分单调性)。
而且因为每层能放的书的数量是一样的,矮书既能放高层又能放矮层,但高书只能放高层,所以最优策略为矮书放矮层,高书放高层。
同理,艺术品放矮层比放高层也要更优。
所以先对每本书和每层书架的高度都升序排序。
接着二分答案,check 中在前 m i d mid mid 层放 y y y 本书,其他层放 x x x 本书,最后看是否放完所有书即可。
代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,x,y,l,r,ans=-1;//先为答案赋值为 -1,若最后还是 -1 则表示一直都没合法过,输出 impossible
vector<int> a,b;
bool check(int k)
{
int j=0;
for(int i=0;i<k&&j<m;i++)//在前 mid 层放 y 本书
{
int cnt=y;
while(cnt--&&j<m&&b[j]<=a[i])
j++;
}
for(int i=k;i<n&&j<m;i++)//在其他层放 x 本书
{
int cnt=x;
while(cnt--&&j<m&&b[j]<=a[i])
j++;
}
return j>=m;//判断书是否放完
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>x>>y;
r=n;
a.resize(n);
b.resize(m);
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<m;i++)
cin>>b[i];
sort(a.begin(),a.end());
sort(b.begin(),b.end());//排序
while(l<=r)//二分答案
{
int mid=(l+r)>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
if(ans==-1)//一直都放不完
cout<<"impossible";
else
cout<<ans;
return 0;
}