uoj #177. 新年的腮雷
阿新 • • 發佈:2018-12-17
題面
題解
早上寫了一篇,就還想再寫一篇
挺不錯的一個題
先來講講部分分吧
第一檔13分的很簡單,直接爆搜就可以了
第二檔11分的也很簡單,直接排個序就可以了
然後有一檔6分的,,這的話,稍作思考,可以發現,每一次一定是選兩個最小的數合起來
然後剩下的檔我就不會了。。
算了一下只可以拿到
蠻低的暴力分吧
其實如果你會第三檔,分的,基本上離正解也不遠了 先說分的吧 正解要想到二分答案,然後倒過來做 那麼問題就變成了,你一開始有一個數,然後每一次,你可以把你的數集裡面的某一個數,把他拆成個數,並且要求拆出來的m個數,都要滿足都比要大。正確性其實挺顯然的。 然後你考慮,滿分的話 問題就等價於,你拆成n個數以後,可以找到一個對應方案,使得每一個數都比對應的大 這個做法其實也不錯的 我們可以進行討論 我們把當前數集的值拿出來,然後看一下目標數集的最大值,再看一下的最小值 如果,那麼顯然,y是不可能由別的東西拆開得到了,因此,找一個剛好比他大的數,對應起來即可 否則就把x拆開,這個,其實正確性也挺顯然的,因為你拆別的不會比拆這個要優 當你得到了n個數的時候,check一下就可以了 時間複雜度顯然是對的 CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
const int N=50005;
int n,m;
int a[N],b[N];
multiset<int> s;
multiset<int> :: iterator it;
bool check (int x)//這個答案行不行
{
s.clear();s.insert(x);
int now= n;
while (s.size()<now)//現在有多少個數了
{
if (s.empty()) return false;
it=--s.end();
if ((*it)-b[1]<a[now])//不行
{
it=s.lower_bound(a[now]);
if (it==s.end()) return false;
s.erase(it);now--;
}
else
{
for (int u=1;u<=m;u++)
s.insert((*it)-b[u]);
s.erase(it);
}
}
int i=1;
for (it=s.begin();it!=s.end()&&i<=now;it++,i++)
if (a[i]>(*it)) return false;
return true;
}
int main()
{
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++) scanf("%d",&a[u]);
for (int u=1;u<=m;u++) scanf("%d",&b[u]);
sort(b+1,b+1+m);sort(a+1,a+1+n);
int l=0,r=1000000000,ans=-1;
while (l<=r)
{
int mid=(l+r)>>1;
if (check(mid)) {r=mid-1;ans=mid;}
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}