洛谷团队内部赛_7月月赛_题解

比赛题目来自各个OJ,经过数据加强

目录

T0: 送分水题

输入格式:
一行,两个整数a, b

输出格式:
一行,一个整数a * b

说明

0 <= a, b <= 2147483648


由于a和b都是<=2147483648的,所以它们乘积可能超长整型哒。。。
然而!用unsigned long long就好了。。。不用写高精度乘法的。
代码:

【过水已隐藏】

T1: 斐波那契和……欧几里得(???)1

输入格式:
一个n,一个m。都是正整数。

输出格式:
gcd(第n个斐波那契数,第m个斐波那契数)

输出这个公约数的后8位就好了(前面的0不要)

说明

1<=n,m<=10^9


这题我给的数据比较水所以这样就能过了:

#include <cstdio>
#include <iostream>
#include <algorithm> 

using namespace std;

long long n, m, a[1000001];

int gcd(long long x, long long y)
{
    if (!min(x, y))
        return max(x, y);
    return gcd(min(x, y), max(x, y) % min(x, y));
}

int main()
{
    cin >> n >> m;
    long long q = gcd(n, m);
    a[1] = 1;
    a[2] = 1;
    for (int i = 3; i <= q; i++)
        a[i] = (a[i - 1] + a[i - 2]) % 100000000;
    cout << a[q];
    return 0;
}

这样就好了。

有这么一个著名式子:gcd(f(n), f(m))=f(gcd(n, m))。证明有一点难,但是这个式子应该听说过的吧?
以下是luogu ID 为浅色调 巨佬的证明:

设n < m, f[n]=a, f[n+1]=b
则f[n+2]=a+b, f[n+3]=a+2b, … f[m]=f[m-n-1]a+f[m-n]b
因为f[n]=a, f[n+1]=b, f[m]=f[m-n-1]a+f[m-n]b
所以f[m]=f[m-n-1]*f[n]+f[m-n]*f[n+1]
又因为gcd(f[n], f[m])=gcd(f[n],f[m-n-1]*f[n]+f[m-n]*f[n+1])
而f[n]|f[m-n-1]*f[n]
所以gcd(f[n],f[m-n]*f[n+1])
再证一个引理:gcd(f[n],f[n+1])=1
证:由欧几里得定理知gcd(f[n],f[n+1])=gcd(f[n],f[n+1]-f[n])=gcd(f[n],f[n-1])=gcd(f[n-2],f[n-1])=……=gcd(f[1],f[2])=1
得证。
由引理和gcd(f[n],f[m])=gcd(f[n],f[m-n]*f[n+1])
所以gcd(f[n],f[m])=gcd(f[n],f[m-n])
即gcd(f[n],f[m])=gcd(f[n],f[m%n])
继续递归,将m1=m%n, 则gcd(f[n],f[m])=gcd(f[n%m1],f[m1])

不难发现整个递归都在求解gcd(n, m)
最后递归到出现f[0]时,此时的f[n]就是所求gcd。
q.e.d.

之前说了出的数据比较水不会TLE。。。但之前的代码不是标算。
以下巨佬 浅色调 标准答案:(矩阵加速好可怕)

#include <bits/stdc++.h>
#define il inline
#define ll long long
#define mem(p) memset(&p,0,sizeof(p))
using namespace std;
const ll mod=1e8;
ll n,m;
struct mat{ll a[3][3],r,c;};
il mat mul(mat x,mat y)
{
    mat p;
    mem(p);
    for(int i=0;i<x.r;i++)
        for(int j=0;j<y.c;j++)
            for(int k=0;k<x.c;k++)
    p.a[i][j]=(p.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
    p.r=x.r,p.c=y.c;
    return p;
}
il void fast(ll k)
{
    mat p,ans;
    mem(p),mem(ans);
    p.r=p.c=2;
    p.a[0][0]=p.a[0][1]=p.a[1][0]=1;
    ans.r=1,ans.c=2;
    ans.a[0][0]=ans.a[0][1]=1;
    while(k)
    {
        if(k&
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值