打卡信奥刷题(3409)用C++实现信奥题 P10091 [ROIR 2022] 分数排序 (Day 2)
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 n≤50 |
| 2 2 2 | 13 13 13 | n ≤ 500 n\le500 n≤500 |
| 3 3 3 | 15 15 15 | q , c i ≤ 100 q,c_i\le100 q,ci≤100 |
| 4 4 4 | 21 21 21 | c i ≤ 10 5 c_i\le10^5 ci≤105 |
| 5 5 5 | 37 37 37 |
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 10 5 1 \leq n \leq 10^5 1≤n≤105, 1 ≤ q ≤ 10 5 1 \leq q \leq 10^5 1≤q≤105 且 q ≤ n 2 , n × q ≤ 10 5 q \leq n^2,n\times q\le10^5 q≤n2,n×q≤105(所以实际上 q ≤ 1000 10 3 ≈ 2154 q\le1000\sqrt[3]{10}\approx2154 q≤1000310≈2154), 1 ≤ a i , b i ≤ 10 6 1 \leq a_i,b_i \leq 10^6 1≤ai,bi≤106, 1 ≤ c i ≤ n 2 1 \leq c_i \leq n^2 1≤ci≤n2。
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考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
更多推荐
所有评论(0)