东北林业大学 23ACM蓝桥杯训练 4 题解

前言:

  今天这些题涉及到了最小公约数(辗转相除法,也叫欧几里得算法),还有快数模取幂,有些题目我自己没想出来,看了其他大佬的题解才想到。

正文:

  Problem:A 最大公约数和最小公倍数:

#include<bits/stdc++.h>
using namespace std;
int gcd(int x,int y){
	int r=x%y;
	while(r){
		x=y;
		y=r;
		r=x%y;
	}
	return y;
}
int lcm(int x,int y){
	return x*y/gcd(x,y);
}
int main(){
	int a,b;
	while(cin>>a>>b){
		cout<<gcd(a,b)<<" "<<lcm(a,b)<<endl;
	}
	return 0;
} 

解法如提示所说。

Problem:B 又见GCD:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int gcd(int a, int b){
    return b == 0 ? a : gcd(b, a % b);
}
int main()
{
    int a, b;
    while(cin >> a >> b){
        for(int i = b * 2;; i += b){
            if(gcd(i, a) == b){
                cout << i << endl;
                break;
            }
        }

    }
    return 0;
}

通过遍历所有可能(注意c只是不等于b,可以大于也可以小于),来找最小c。

Problem:C 多个数的最大公约数:

#include<bits/stdc++.h>
using namespace std;
int gcd(long long x,long long y){
	long long r=x%y;
	while(r){
		x=y;
		y=r;
		r=x%y;
	}
	return y;
}
int work(long long a[],int n){
	long long ans=a[1];
	for(int i=2;i<=n;i++){
		ans=gcd(ans,a[i]);
	}
	return ans;
}
int main(){
	int n;
	long long a[19];
	while(cin>>n){
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		cout<<work(a,n)<<endl;
	}
	return 0;
}

多个数的最大公约数就是用前面两数的最大公约数来与下个数求最大公约数,不断取值,最后一个值为答案。

Problem:D 多个数的最小公倍数:

#include<bits/stdc++.h>
using namespace std;
long long gcd(long long a, long long b){
return b == 0 ? a : gcd(b, a % b);
}
long long lcm(long long a, long long b){
return a / gcd(a, b) * b;
}
int main() {
	long long n;
	while (cin >> n){
		long long ans;
		cin >> ans;
		for (int i = 1;i<n;i++) {
		long long x;
		cin >> x;
		ans = lcm(ans, x);
		}
		cout << ans << endl;
	}
	return 0;
}

同上题一样,逐个求两个数的最小公倍数。

Problem:E LCM&GCD:

数据加强后暴力过不了,我看大佬了的题解才会。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,a,b,x,y,ans;
int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>x>>y;
        ans=0;
        if(y%x!=0){printf("0\n");continue;}//最小公倍数不是最大公约数的倍数,直接输出0
        y=y/x;//将y缩小到y1
        for(a=1;a*a<=y;a++)//在[1,y1]区间内暴力遍历所有a1的取值,a每次+1
        {
            if(y%a==0)//满足y1=a1*b1,则b1=y1/a1,首先必须满足y1%a1==0
            {
                b=y/a;//直接得到b1的取值
                if(__gcd(a,b)==1)//gcd(a1,b1)==1则满足条件
                {
                    if(a*a==y)ans++;//特判a1*a1=y的情况,答案+1
                    else ans+=2;//其他情况答案+2
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

我解释下这个的做法啊,因为两个数的最大公约数与最小公倍数乘积与两个数的乘积相等,就有x*y=a*b(a,b的最小公倍数为y,最大公因数为x),同除以x*x,得y/x=(a/x)*(b/x),令y1=y/x,a1=a/x,b1=b/x。y1=a1*b1,且a1∈[1,y1],这样化简之后,再遍历[1,sqrt(y1)](只需遍历到 根号y1 即可)找满足gcd(a1,b1)==1的情况,也就是gcd(a,b)==x同时lcm(a,b)==y的情况(我觉得这想法真nb,也真的很巧妙)。

Problem:F 人见人爱gcd:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    ll a,b,n;
    while(~scanf("%lld",&n))
    {
        while(n--)
        {
            scanf("%lld%lld",&a,&b);
            printf("%lld\n",a*a-2*b*gcd(a,b));
        }
    }
    return 0;
}

这题是个数学证明题,因为2*x*y=2*gcd(x,y)*lcm(x,y),又(x+y)^2-2*x*y==x^2+y^2,设x=k1*t,y=k2*t,gcd(a,b)=gcd(k1*t+k2*t,k1*k2*t),因为k1与k2互质 ,所以gcd(a,b)=t=gcd(x,y)。

Problem:G 高木同学的因子:

#include <bits/stdc++.h>
using namespace std;
long gcd(long a,long b)
{
    return b?gcd(b,a%b):a;
}
long lcm(long a,long b)
{
    return a*b/(gcd(a,b));
}

int main()
{
    long long x,y,t,sum=0;
    int i;
    cin>>x>>y;
    t=gcd(x,y);
    for(i=1;i*i<t;i++)
    {
        if(t%i==0)sum+=2;
    }
    if(i*i==t)sum++;
    cout<<sum<<endl;
    return 0;
}

先求最大公因数,再找最大公因数的因数。

Problem:H 快速幂取模:

#include<bits/stdc++.h>
#define ll long long
ll quickMod(ll a, ll b, ll c)
{
  ll ans = 1;
  a = a % c;
  while(b)
  {
    if(b&1) ans = (ans * a) % c;
    b = b >> 1;
    a = (a * a) % c;
  }
  return ans;
}
using namespace std;
int main(){
	ll a,b,c;
	while(cin>>a>>b>>c){
		cout<<quickMod(a,b,c)<<endl;
	}
	return 0;
}

快数模取幂算法,用于简化计算。

Problem:I 库特的数学题:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mit=1e9+7;
ll quickmod(ll a,ll b,ll c){
	ll ans=1;
	a=a%c;
	while(b){
		if(b&1)ans=ans*a%c;
		a=a*a%c;
		b/=2;
	}
	return ans;
}
int main(){
	ll n;
	while(cin>>n){
		ll x=quickmod(3,n,1000000007);
		cout<<2*x%(1000000007)<<endl;
	}
	return 0;
}

a[n]=2*pow(3,n),也是快数模取幂。

Problem:J 异或方程解的个数:

#include <bits/stdc++.h>
using namespace std;
int x,ans;
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>x)
    {
        ans=1;
        while(x)
        {
            if(x&1)ans=ans*2;
            x=x/2;
        }
        printf("%d\n",ans);
    }
    return 0;
}

公式:n+x==n^x+n&x<<1,条件:n-x==n^x 结果:x==x&n (也可以通过找规律求得)。

后记:

寒假前就上到这里了,我后面可能会继续用网课来学习,希望自己能拥有更大的热情。

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值