补题 2020牛客多校第四场

这篇博客介绍了三道数学竞赛题目,包括线性关系的判断和基本与更复杂的最大公约数问题。对于F题,通过三角形性质判断线段是否平行;B题求解涉及质因数的递归问题;H题则探讨在限制条件下如何最大化选择数对使得它们的最大公约数大于1。

F-Finding the Order

在这里插入图片描述
在这里插入图片描述

题意

大水题,A和B在一条线上,C和D在一条线上,给定AC,AD,BC,BD的距离,判断是AB||CD还是AB||DC(C和D的位置不同,“CD"和“DC”不一样)

思路

根据三角形两边之和大于第三边,中间交叉两边之和必定大于两边的两条线之和,判断AC+BD和AD+BC的大小即可

代码

#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int a,b,c,d;
cin>>a>>b>>c>>d;
if(a+d>b+c)puts("AB//CD");
else puts("AB//DC");
}
return 0;
}

B-Basic Gcd Problem

在这里插入图片描述
在这里插入图片描述

题意

给你一个n和c,计算在这里插入图片描述

思路

我们发现每一次递归都会乘一次c,而每一次递归的条件便是x是否为质数,所以可以得出最后的答案为cn的质因子个数

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const int mod = 1e9 + 7;
ll qmi(int a,int b){ll res=1%mod;while(b){if(b&1)res=res*a%mod;b>>=1;a=(ll)a*a%mod;}return res;}
int ans[N];
void op(int x){
    if(ans[x])return;
    for(int i = 2;i <= x / i; i ++){
        if(x % i == 0){
            op(x / i);
            ans[x] = ans[x / i] + 1;
            return ;
        }
    }
    ans[x] = 1;
    return ;
}
void init(){
    ans[0] = 1;
    for(int i = 2;i < N;i ++)op(i);
}
int main(){
init();
int _;
scanf("%d",&_);
while(_--){
    int n,c;
    scanf("%d%d",&n,&c);
    printf("%lld\n",qmi(c,ans[n]));
}
	return 0;
}

H-Harder Gcd Problem

在这里插入图片描述
在这里插入图片描述

题意

1-n的数,从中选出m对数,使gcd(a1,bi)>1,让m尽可能大,并输出这m对对应的数字

思路(参考牛客题解第二篇)

m肯定是固定的,可以确定m是(n-1-大于n/2的质数个数)/2,因为1和大于n/2的质数肯定不能匹配。接下来对于质数及其倍数构成的集合,如果当前集合是偶数个,那随意匹配,如果是奇数个,保留当前质数*2(使留下的数的个数最多),剩下的数偶数个随意匹配。

代码

#include<bits/stdc++.h>
#define fi first
#define se second

using namespace std;

typedef long long ll;
const int N  = 2e5+5;
bool st[N],vis[N];
int p[N],idx,sum[N];
int ans1[N],ans2[N];
void init(){
    st[1] = 1;
    for(int i = 2; i <=100000; i ++){
        if(!st[i])p[++idx] = i;
        for(int j = 1;j <= idx && p[j] * i <= 100000;j ++){
            st[p[j] * i] = 1;
            if(i % p[j] == 0)break;
        }
    }
}
void solve(){
	int n,cnt = 0;
    cin >> n;
    for(int i = 1; i <= n; i ++)vis[i] = 0;
    int k = n / 2;
    int pos = upper_bound(p + 1,p + 1 + min(idx,k),k) - p -1;
	for(int i = pos;i >= 1;i --){
        int now = 0;
        sum[++now] = p[i];
        for(int j = 2;p[i] * j <= n; j ++){
            int mul = p[i] * j;
            if(!vis[mul])sum[++now] = mul;
        }
        if(now & 1){
            ans1[++cnt] = sum[1];
            ans2[cnt] = sum[3];
            vis[sum[1]] = 1;
            vis[sum[3]] = 1;
            for(int i = 4;i <= now ;i+=2)
            ans1[++cnt] = sum[i],
            ans2[cnt] = sum[i+1],
            vis[sum[i]] = 1,
            vis[sum[i+1]] = 1;
        }
        else {
            for(int i = 1; i <= now; i += 2)
            ans1[++cnt] = sum[i],ans2[cnt] = sum[i + 1],
            vis[sum[i]] = 1,vis[sum[i + 1]] = 1;
        }
	}
    printf("%d\n",cnt);
    for(int i = 1;i <= cnt;i ++)
    printf("%d %d\n",ans1[i],ans2[i]);
}

int main(){
init();
int _;cin>>_;while(_--)solve();
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值