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;
}
$$We're \; here \; to \; put \; a \; dent \; in \; the \; universe.$$