HDU5970

分享二合一 第四弹

HDU5970 最大公约数

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5970

显然直接暴力硬上gcd时间爆炸。

但是根据欧几里得算法,我们知道 \(gcd(a, b)=gcd(b,a\) % \(b\))

然后显然这个在这道题里的\(f(a,b)\)里也适用

再然后,以一个m为基数,对于所有的n,余数即为0~m-1

然后就可以统计同余的有多少个,再根据规律一片片地求

这应该就是很多人说的m2的求法...然鹅这道题有个很恶心的向下取整

这么做就会出现多一少一的问题...所以pass掉...

然后正解先推荐:https://www.cnblogs.com/liangyongrui/p/6048990.html

自己的我回头再写。。。

怎么交怎么超时...明明我看别人都是这么写的...

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
#define ll long long
#define Game return 
#define Over 0

inline ll read(){
    ll x = 0,f = 1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch = getchar();
    }
    while(ch>='0'&&ch<='9'){
        x = (x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x * f;
}

ll f(ll x, ll y, ll &c, ll &g){
    c = 0;
    ll t;
    while(y > 0){
        c += 1;
        t = x % y;
        x = y;
        y = t;
    }
    g = x;
    return c * x * x;
}

int main(){
    ll n, m, p;
    int t;
    cin >> t;
    for(int cnt = 1; cnt <= t; cnt++){
        ll ans = 0, g, c;
        ll a1, num, d;
        //scanf("%lld %lld %lld", &n, &m, &p);
        n = read(), m = read(), p = read();

        for(int j = 1; j <= m; j++){
            for(int i = 1; i <= j && i <= n; i++){

                ll tmp = f(i, j, c, g);

                for(int k = 0; k < c; k++){
                    if(i + k * j > n) break;
                    a1 = (i + k * j) * j / tmp;
                    d = c * j * j /tmp;
                    num = (n - (i + k * j)) / (c * j) + 1;
                    ans = ((ans + a1 * num) % p + num * (num - 1) / 2 % p * d % p) % p;
                }
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}
posted @ 2020-05-30 18:06  zfio  阅读(93)  评论(0编辑  收藏  举报