毒瘤C題,考場卡我1個小時
首先,這道題難點在哪里?它的最大值與最小值都是浮動的。
怎么辦?把最小/最大值固定!
以把最小值固定為例,我們枚舉每個音符,並枚舉它使用哪條琴弦,將它此時的位置強制其作為最小值(設為\(minx\))。
同時,我們令其他音符不作為最小值,即其他的音符的位置不能小於最小值。
接下來,我們只需計算每個音符的最小位置(但不小於最小值),在這些音符中取 \(\max\) 即可。
直接的想法是枚舉其他的所有音符,尋找滿足 \(b_i-a_j \ge minx\) 最大 \(a_j\) (此時 \(b_i-a_j\) 最小)。
很明顯,這樣做是 \(O(n)\) 的。然而,我們要枚舉 \(6n\) 個最小值,時間復雜度為\(O(n^2)\) (把常數項省掉了)…
略加思考,我們發現並不是所有的音符都要枚舉一遍。我們把\(a、b\)數組分別從小到大排序,並把\(a\)數組去重(原因后面講),那么最悲慘的音符(霧) 肯定是那些可以用 \(a_{j-1}\) 的琴弦,但正好用不了 \(a_j\) 的琴弦的音符中最大的一個。當然,如果存在音符連 \(a_1\) 都用不了,直接判定當前最小值不合法,並枚舉下一個最小值。
舉個例子:\(a\)數組為 \([1,3,5]\) (去重以后),\(b\)數組為 \([4,5,6,6,7]\),\(minx\)為\(3\)。
那么,\(5、7\)是最悲慘的音符,因為\(5\)是可以用琴弦\(a_1\)但用不了琴弦\(a_2\)(有\(4、5\)兩個音符)中最大的音符,\(7\)是可以用琴弦\(a_2\)但用不了琴弦\(a_3\)中最大的音符。顯然,最大的位置將在最悲慘的音符中產生。
由於我們對 \(b\) 數組排過序,因此對每一條琴弦,直接二分查找最大的 \(b_i\) ,使 \(b_i-a_j < minx\) 即可。
於是,我們只要找到這些音符即可。這些音符最多不超過\(6\)個。時間復雜度 \(O(n \log n)\) 。
最后說一句,為什么\(a\)要去重?因為我們要找可以用 \(a_{j-1}\) 的琴弦但用不了 \(a_j\) 的琴弦的音符,如果存在重復,即 \(a_{j-1}=a_j\) ,則可能這個音符 \(a_{j-1}\) 的琴弦、 \(a_j\) 的琴弦都用不了,明顯不符。
\(Code:\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
ll a[10],n,b[100010],pos[10],cnt;
ll ans=1e18;
int main(){
for(int i=1;i<=6;i++) scanf("%lld",&a[i]);
sort(a+1,a+7);cnt=unique(a+1,a+7)-a-1;//去重
cin>>n;
for(int j=1;j<=n;j++) scanf("%lld",&b[j]);
sort(b+1,b+n+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=cnt;j++){
ll minx=b[i]-a[j],maxn=0,last=0; //枚舉minx
if(b[1]-a[1]<minx) goto fail;
for(int k=2;k<=cnt;k++){
last=lower_bound(b+last+1,b+n+1,minx+a[k])-b-1;//二分查找
maxn=max(maxn,b[last]-a[k-1]);//更新最大位置
}
for(int k=cnt;k>=1;k--){
if(b[n]-a[k]>=minx){
maxn=max(maxn,b[n]-a[k]); //最大的音符特殊處理一下
break;
}
}
ans=min(ans,maxn-minx);//更新答案
fail:;
}
}
cout<<ans<<endl;
return 0;
}
