#C241115B. B


#C241115B. B

标签(Label)

  • 根号分治
  • 数学

网址(Website)

题目详情 - B - Super

题解 - B - Super

题目(Problem)

样例

输入数据 1

2 4
1 2
3 4
5 6

输出数据 1

10

【样例1解释】

集合 $S = {9, 10, 10, 10, 11, 11, 11, 12}$,第 $4$ 小的值是 $10$ 。

输入数据 2

10 40
11 9 13 12 15 11 11 2 11 17
3 1 10 2 12 18 9 11 11 15
14 9 4 14 16 9 20 2 1 18

输出数据 2

14

【样例3】

见选手目录下的 set/set3.inset/set3.ans

【样例4】

见选手目录下的 set/set4.inset/set4.ans

【样例5】

见选手目录下的 set/set5.inset/set5.ans

【样例6】

见选手目录下的 set/set6.inset/set6.ans

题解(Solution)

这道题很卡常,不要用结构体。

肯定先对每个数字排序,这个不必说。

33分

这道题的答案满足单调性(即对于最后的答案,小于它的点排名一定小于 $k$ ,否则一定大于 $k$)。

有一个很简单的想法就是二分 $mid$ ,求出排名。可以暴力枚举 $a_{i}$ ,那么就是要求 $b_j+c_k\le mid-a_i$ 的数有多少个,这个时候就可以直接枚举 $j$ ,发现 $j$ 变大的过程中 $b_j$ 变大,此时 $c_k$ 只能变小,则 $k$ 的范围一定变小,那么可以双指针 $O(n)$ 解决这个问题。

时间复杂度 $O(n^2\log A)$ 。

52分

双指针必须是 $O(n)$ 的时间复杂度,不好优化。

只能考虑压缩数组来解决问题,发现第 $3$ 个点的 $k\le 10^5$ ,那就只需要计算出 $b_j$ 和 $c_k$ 能组成的前 $k$ 小的数字,然后再二分与 $a_i$ 暴力匹配,时间复杂度 $O(k\log A)$

100分

提供两种做法:

人类智慧法

发现当 $k\le 10^9$ 时,我们枚举的 $b_j+c_k$ 其实没必要到 $10^9$ ,假设我们计算 $S=10^6$ 的数据(时间复杂度 $O(S\log S)$ ,肯定能过),我们得出前 $i$ 个 $a_i$ 最多可以拿到 $i\times S$ 的排名,假定答案在我们当前计算的 $a_i,b_j,c_k$ 内,那我们就能得出正确答案,而出题人出的数据是随机的。

实际可以自己造数据,看一下开多少时间和空间能过,大概率是对的。

ps:学校电脑里面的 Linux 本机跑 $2$ 秒,交到我们的超卡 $\text{OJ}$ 上面都才 $0.7$ 秒。。。简直无语 ̄へ ̄

正解

出题者题解

代码(Code)

33分
#include<bits/stdc++.h>
#include<vector>
#define For(i,l,r) for(int i=l;i<=r;i++) 
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int> 
#define int long long
#define x first
#define y second
inline int rd(){
	bool f=false;char c;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 201234;
const int S = 1e8;
bool ST;

int a[N],b[N],c[N];
int n,K,ans;

inline bool chk(int mid){
	int res = 0;
	for(int i=1;i<=n && a[i]<=mid;i++){
		for(int j=1,k=n;j<=n && a[i]+b[j]<=mid;j++){
			while(k && c[k] > mid-a[i]-b[j]) k--;
			res += k;
		}
	}return res >= K;
}

void Solve(){
	n=rd(), K=rd();For(i,1,n) a[i]=rd();For(i,1,n) b[i]=rd();For(i,1,n) c[i]=rd();
	sort(a+1,a+n+1), sort(b+1,b+n+1), sort(c+1,c+n+1);
	a[n+1] = b[n+1] = c[n+1] = inf;
	
	int l=0,r=3e9,mid;
	while(l<=r){
		mid = (l+r)>>1;
		if(chk(mid)) ans=mid,r=mid-1;
		else l=mid+1;
	}printf("%lld\n", ans);
}

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	int Tt=1;double Tim=clock();
	while(Tt--) Solve();
	return cerr<<"TIME:"<<(clock()-Tim)/CLOCKS_PER_SEC,0;
}
100分(人类智慧)
#include<bits/stdc++.h>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int>
#define int long long
#define x first
#define y second
#define in(x,l,r) (l<=x && x<=r)
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}template<typename G>
void write(G x){
	if(x<0) putchar('-'),write(-x);
	else if(x<=9) putchar(x+'0');
	else write(x/10), putchar(x%10+'0');
}constexpr int inf = 0x3f3f3f3f3f3f3f3f;
constexpr int N = 201234;
constexpr int S = 2000000;
bool ST;

int a[N],b[N],c[N],d[S+5];
int n,k,cnt;
priority_queue<P> q;

int calc(int mid){
	int res = 0;
	for(int i=1,j=cnt;i<=n && a[i]<=mid;i++){
		while(j && a[i]+d[j]>mid) j--;
		res += j;
	}return res;
}

void Solve(){
	n=rd(),k=rd();For(i,1,n) a[i]=rd();For(i,1,n) b[i]=rd();For(i,1,n) c[i]=rd(); 
	sort(a+1,a+n+1), sort(b+1,b+n+1), sort(c+1,c+n+1);
	For(i,1,n) q.emplace(-b[i]-c[1],1);
	while(q.size() && cnt<=S){
		d[++cnt] = -q.top().x;
		int p = q.top().y;q.pop();
		if(p<n) q.emplace(-d[cnt]+c[p]-c[p+1], p+1);
	}
	int l=a[1]+b[1]+c[1],r=a[n]+b[n]+c[n],res=-1;
	while(l<=r){
		int mid = (l+r)>>1;
		if(calc(mid) >= k) r=mid-1,res=mid;
		else l=mid+1;
	}write(res), putchar('\n');
}

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	int T = 1;double Tim = clock();
	while(T--) Solve();
	return cerr<<"TIME:"<<(clock()-Tim)/CLOCKS_PER_SEC,0;
}
100分
#include<bits/stdc++.h>
#include<vector>
#include<queue>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int>
#define int long long 
#define x first
#define y second
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 50123;
const int M = 20123456;
bool ST;

int a[N],b[N],c[N];
int n,m,B,S,ans;

priority_queue<pair<int,P>> q;
int g[M],cnt;

inline bool check(int mid){
	int res = 0;
	For(i,1,B) for(int j=1,k=n;j<=n;j++){
		while(k && b[j]+c[k] > mid-a[i]) k--;
		res += k;
		if(res >= m) return true;
	}
	For(i,B+1,n){
		res += upper_bound(g+1,g+cnt+1,mid-a[i])-g-1;
		if(res >= m) return true;
	}return false;
}

void Solve(){
	n=rd(), m=rd(), B=min((int)(sqrt(double(m)/n+1)),n), S=(m+B-1)/B;
	For(i,1,n) a[i]=rd();For(i,1,n) b[i]=rd();For(i,1,n) c[i]=rd();
	sort(a+1,a+n+1), sort(b+1,b+n+1), sort(c+1,c+n+1);
	For(i,1,n) q.push({-b[i]-c[1],{i,1}});
	while(q.size() && cnt<S){
		P x=q.top().y;q.pop();
		g[++cnt] = b[x.x]+c[x.y];
		if(x.y<n) q.push({-b[x.x]-c[x.y+1],{x.x,x.y+1}});
	}
	int l=a[1]+b[1]+c[1], r=a[n]+b[n]+c[n], mid;
	while(l<=r){
		mid = (l+r)>>1;
		if(check(mid)) r=mid-1, ans=mid;
		else l=mid+1;
	}printf("%lld\n",ans);
}

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	int Tt=1;double Tim=clock();
	while(Tt--) Solve();
	return cerr<<"TIME:"<<(clock()-Tim)/CLOCKS_PER_SEC,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录