P10091 [ROIR 2022] 分数排序 (Day 2)

题目背景

翻译自 ROIR 2022 D2T2

题目描述

有两个由 n n n 个不同整数组成的序列 A = [ a 1 , a 2 , … , a n ] A = [a_1, a_2, \dots , a_n] A=[a1,a2,,an] B = [ b 1 , b 2 , … , b n ] B = [b_1, b_2, \dots , b_n] B=[b1,b2,,bn]。将它们组合成 n 2 n^2 n2 个分数,形式为 a i b j \frac{a_i}{b_j} bjai,并将每个分数约分后按递增顺序排序。

给定一个数字 q q q q q q 个整数 c 1 , c 2 , … , c q c_1, c_2, \dots , c_q c1,c2,,cq。对于每个 c i c_i ci,请输出上面所说的 n 2 n^2 n2 个分数中第 c i c_i ci 小的分数。

输入格式

第一行包含两个整数 n n n q q q

第二行包含 n n n 个不同的整数 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,,an

第三行包含 n n n 个不同的整数 b 1 , b 2 , … , b n b_1, b_2, \dots, b_n b1,b2,,bn

第四行包含 q q q 个不同的整数 c 1 , c 2 , … , c q c_1, c_2, \dots, c_q c1,c2,,cq

输出格式

输出 q q q 行。第 i i i 行输出按递增顺序得到的第 c i c_i ci 个分数。分数 p q \frac{p}{q} qp 应以 p q 的格式输出,并且应为最简分数。

输入输出样例 #1

输入 #1

4 8
3 4 1 2
2 3 4 5
1 16 2 4 5 6 10 15

输出 #1

1 5
2 1
1 4
2 5
1 2
1 2
4 5
3 2

说明/提示

在样例中,初始的分数列表如下:

[ 3 2 , 3 3 , 3 4 , 3 5 , 4 2 , 4 3 , 4 4 , 4 5 , 1 2 , 1 3 , 1 4 , 1 5 , 2 2 , 2 3 , 2 4 , 2 5 ] , \left[ \frac{3}{2}, \frac{3}{3}, \frac{3}{4}, \frac{3}{5}, \frac{4}{2}, \frac{4}{3}, \frac{4}{4}, \frac{4}{5}, \frac{1}{2}, \frac{1}{3}, \frac{1}{4}, \frac{1}{5}, \frac{2}{2}, \frac{2}{3}, \frac{2}{4}, \frac{2}{5} \right], [23,33,43,53,24,34,44,54,21,31,41,51,22,32,42,52],

经过约分后,得到:

[ 3 2 , 1 1 , 3 4 , 3 5 , 2 1 , 4 3 , 1 1 , 4 5 , 1 2 , 1 3 , 1 4 , 1 5 , 1 1 , 2 3 , 1 2 , 2 5 ] , \left[ \frac{3}{2}, \frac{1}{1}, \frac{3}{4}, \frac{3}{5}, \frac{2}{1}, \frac{4}{3}, \frac{1}{1}, \frac{4}{5}, \frac{1}{2}, \frac{1}{3}, \frac{1}{4}, \frac{1}{5}, \frac{1}{1}, \frac{2}{3}, \frac{1}{2}, \frac{2}{5} \right], [23,11,43,53,12,34,11,54,21,31,41,51,11,32,21,52],

最后按递增顺序排序,得到:

[ 1 5 , 1 4 , 1 3 , 2 5 , 1 2 , 1 2 , 3 5 , 2 3 , 3 4 , 4 5 , 1 1 , 1 1 , 1 1 , 4 3 , 3 2 , 2 1 ] . \left[ \frac{1}{5}, \frac{1}{4}, \frac{1}{3}, \frac{2}{5}, \frac{1}{2}, \frac{1}{2}, \frac{3}{5}, \frac{2}{3}, \frac{3}{4}, \frac{4}{5}, \frac{1}{1}, \frac{1}{1}, \frac{1}{1}, \frac{4}{3}, \frac{3}{2}, \frac{2}{1} \right]. [51,41,31,52,21,21,53,32,43,54,11,11,11,34,23,12].

本题使用捆绑测试。

子任务 分值 特殊性质
1 1 1 14 14 14 n ≤ 50 n\le50 n50
2 2 2 13 13 13 n ≤ 500 n\le500 n500
3 3 3 15 15 15 q , c i ≤ 100 q,c_i\le100 q,ci100
4 4 4 21 21 21 c i ≤ 10 5 c_i\le10^5 ci105
5 5 5 37 37 37

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 10 5 1 \leq n \leq 10^5 1n105 1 ≤ q ≤ 10 5 1 \leq q \leq 10^5 1q105 q ≤ n 2 , n × q ≤ 10 5 q \leq n^2,n\times q\le10^5 qn2,n×q105(所以实际上 q ≤ 1000 10 3 ≈ 2154 q\le1000\sqrt[3]{10}\approx2154 q1000310 2154), 1 ≤ a i , b i ≤ 10 6 1 \leq a_i,b_i \leq 10^6 1ai,bi106 1 ≤ c i ≤ n 2 1 \leq c_i \leq n^2 1cin2

C++实现

#include<bits/stdc++.h>
using namespace std;
int n,q;
int a[100010],b[100010];
long long check(long double x){
	int j=0;
	long long sum=0;
	for(int i=1;i<=n;i++){
		while((long double)a[j+1]<(long double)x*b[i]&&j<n) j++;
		sum+=j;
	}
	return sum;
}
bool p[1000010];
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),p[a[i]]=1;
	for(int i=1;i<=n;i++)
		scanf("%d",&b[i]);
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	while(q--){
		long long c;
		scanf("%lld",&c);
		long double l=(long double)a[1]/b[n],r=(long double)a[n]/b[1];
		while(r-l>=1e-13){//精度要够高同时不能太高
			long double mid=(l+r)/2;
			if(check(mid)>=c) r=mid;
			else l=mid;
		}
		for(int i=1;i<=n;i++){
			int fz=round(l*b[i]);//尝试l*b[i]做分子
			if(fz<=1e6&&p[fz]&&abs(fz-l*b[i])<1e-7){
				int g=__gcd(fz,b[i]);
				printf("%d %d\n",fz/g,b[i]/g);
				break;
			}
		}
	}
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

更多推荐