题解 AT2384 【Kenus the Ancient Greek】
什么玩意,没人肝正解的吗?
第一问很好做,用斐波那契数就可以,主要难在第二问,统计满足条件的二元组的数量。
不妨只统计满足
那么
excellent pair 的数量是很少的,excellent pair of 只有恰好 k 个。
给出前面几个 excellent pair:
excellent pair of 1:
excellent pair of 2:
excellent pair of 3:
excellent pair of 4:
仔细观察,考虑怎么预处理 excellent pair 。
excellent pair of k + 1 经过一次 gcd 后一定是一个 good pair of k ,而 good pair of k 都能用 excellent pair of k 表示 。
通过 excellent pair of k ,每个
另外还会多出来一个 excellent of k + 1 是最小的 excellent pair of k
也就是将
综上,可以在
参考实现:
#include <cstdio>
#include <algorithm>
#include <vector>
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef std::pair<ll, ll> par;
struct {
inline operator int () { int x; return scanf("%d", &x), x; }
inline operator ll () { ll x; return scanf("%lld", &x), x; }
template<class T> inline void operator () (T &x) { x = *this; }
template<class T, class ...A> inline void operator () (T &x, A &...a)
{ x = *this; this -> operator ()(a...); }
} read;
const int maxk = 100, mod = 1000000007;
ll fi[maxk];
std::vector<par> excellent[maxk];
int main() {
int k = 1;
fi[0] = fi[1] = 1;
ll lim = 1000000000000000000;
while(fi[k] + fi[k - 1] <= lim) {
++ k;
fi[k] = fi[k - 1] + fi[k - 2];
}
excellent[1].push_back(par(1, 2));
for(int i = 2; i <= k; i ++) {
for(par p : excellent[i - 1])
excellent[i].push_back(par(p.second, p.first + p.second));
excellent[i].push_back(par(fi[i + 1], fi[i + 1] + fi[i - 1]));
}
int q = read;
while(q --) {
ll x = read, y = read;
if(x > y) std::swap(x, y);
int max = 1;
while(max + 2 <= k and fi[max + 1] <= x and fi[max + 2] <= y)
++ max;
ll tot = 0;
for(par p : excellent[max]) {
if(p.first <= x and p.second <= y)
tot += (y - p.second) / p.first + 1;
if(p.second <= x)
tot += (x - p.second) / p.first + 1;
tot %= mod;
}
if(max == 1)
tot += x;
printf("%d %lld\n", max, tot);
}
}