1.预处理先求出1e10范围内的所有完美的数
2.一个有n个值的二叉排序树的个数:
先将这n个数排序,然后 可以选第1个数为根,那么就变成了 构造 0个节点的左子树 与 n-1个节点的右子树
选第2个数为根,那么就变成了 构造1个节点的左子树 与 n-2个节点的右子树
。。。。。
选第k个数为根,那么就变成了 构造 k-1个节点的左子树 与 n-1-k个节点的右子树
那么 F[N] = F[0]*F[N-1] + F[1] * F[N-2] + ......+ F[K] * F[N-1-K] + ......+ F[N-1] * F[0];
这个公式为卡特兰数的公式:
由此可得递推公式为 F[N] = F[N-1] * ( 4 * N - 2 ) / ( N + 1 )
3,由于该公式有 (N+1)^-1 那么对MOD取余的时候要用扩展欧几里得算法
具体见代码,或百度
4.那么有了以上三步之后 只需用二分法求出 1到a有多少个完美数 1到b有多少个完美数 然后通过上面的F[N] 直接得出结果
代码如下:
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define SIZE 110100
const long long MAX = 1e10;
#define MOD 100000007
#define LL long long
LL temp[SIZE], M[SIZE], ans[SIZE];
LL tot = 0, k = 0;
void EGCD( LL a, LL b, LL &x, LL &y ){
if( b == 0 ){
x = 1;
y = 0;
return;
}
EGCD( b, a % b, x, y );
LL tp = x;
x = y;
y = tp - a / b * y;
}
void initial(){
tot = 1;
k = 1;
for( LL i = 2; i < SIZE; i++ ){
LL j = i * i;
while( j <= MAX ){
temp[k++] = j;
j *= i;
}
}
sort( temp + 1, temp + k );
for( LL i = 1; i <= k; i++ ){
if( temp[i] != temp[i+1] ){
M[tot++] = temp[i];
}
}
ans[0] = 0;
ans[1] = 1;
for( LL i = 2; i < SIZE; i++ ){
LL x, y;
EGCD( i + 1, MOD, x, y );
ans[i] = ans[i-1] * ( 4 * i - 2 ) % MOD * ( x % MOD + MOD ) % MOD;
}
}
int main(){
initial();
int T, Case = 1;
LL a, b;
cin >> T;
while( T-- ){
cin >> a >> b;
LL l = 1, r = tot, mid;
while( l < r ){
mid = ( l + r ) / 2;
if( M[mid] >= a ){//每次都求刚好等于a或者大于它的
r = mid;
}else{
l = mid + 1;
}
}
a = r;
l = 1, r = tot;
while( l < r ){
mid = ( l + r ) / 2;
if( M[mid] > b ){//每次求得大于它的
r = mid;
}else{
l = mid + 1;
}
}
b = r;
cout << "Case " << Case++ << ": " << ans[b-a] << endl;
}
return 0;
}