您的位置:首页 > 其它

「6月雅礼集训 2017 Day8」gcd

2017-06-24 19:41 357 查看
【题目大意】

定义times(a, b)表示用辗转相除计算a和b的最大公约数所需步骤。

那么有:

1. times(a, b) = times(b, a)

2. times(a, 0) = 0

3. times(a, b) = times(b, a mod b) + 1

对于$1 \leq x \leq A, 1 \leq y \leq B$,求times(A, B)的最大值,以及有多少对数取到了最大值。

多组数据。

$T \leq 3 \times 10^5, 1 \leq A,B \leq 10^{18}$

【题解】

我们打一个1000以内,times(x, y) = 13的表

# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int N = 1e5 + 10, M = 2e5 + 10, F = 105;
const int mod = 1e9 + 7;

inline ll getll() {
ll x = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}

ll fib[F];

struct pa {
ll a, b;
pa() {}
pa(ll a, ll b) : a(a), b(b) {}
friend bool operator == (pa a, pa b) {
return a.a == b.a && a.b == b.b;
}
friend bool operator < (pa a, pa b) {
return a.a < b.a || (a.a == b.a && a.b < b.b);
}
friend bool operator > (pa a, pa b) {
return a.a > b.a || (a.a == b.a && a.b > b.b);
}
};

vector<pa> g[M];

int times = 0;
inline int gcd(ll a, ll b) {
if(a < b) swap(a, b);
if(b == 0) return a;
++times;
return gcd(b, a%b);
}

inline int calc(ll a, ll b) {
times = 0;
gcd(a, b);
return times;
}

inline void gg(int x) {
pa t; g[x].clear();
for (int i=0; i<g[x-1].size(); ++i) {
t = g[x-1][i];
ll y = t.b; swap(t.a, t.b);
for (t.b += y; t.b <= fib[x+2]; t.b += y)
if(calc(t.a, t.b) == x) g[x].push_back(t);
}
sort(g[x].begin(), g[x].end());
g[x].erase(unique(g[x].begin(), g[x].end()), g[x].end());
}

ll A, B, ans, tem;
inline void sol() {
A = getll(), B = getll();
if(A > B) swap(A, B);
ans = 1; tem = 0;
for (int i=2; i<90; ++i)
if(fib[i] <= A && fib[i+1] <= B) ans = i;
else break;
printf("%d ", ans);
if(ans == 1) {
printf("%d\n", A % mod * (B % mod) % mod);
return ;
} else {
for (int i=0; i<g[ans-1].size(); ++i) {
ll a = g[ans-1][i].a, b = g[ans-1][i].b;
if(b <= A) tem += (B-a)/b, tem %= mod;
if(b <= B) tem += (A-a)/b, tem %= mod;
}
}
printf("%lld\n", tem);
}

int main() {
//    freopen("gcd.in", "r", stdin);
//    freopen("gcd.out", "w", stdout);
fib[0] = 1, fib[1] = 1;
for (int i=2; i<=90; ++i) fib[i] = fib[i-1] + fib[i-2];
g[1].push_back(pa(1ll, 2ll)), g[1].push_back(pa(1ll, 3ll));
for (int i=2; i<=88; ++i) gg(i);
int T; cin >> T;
while(T--) sol();
return 0;
}


View Code
upd: 加了个读入优化跑了rk2 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: