Lightoj 1170 卡特兰数+扩展欧几里得算法

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;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值