perfect power 是指可以表示成x^y(x>1,y>1)的数,给一个区间[A,B]求由这个区间的所有perfect能组成多少种不同形态的二叉查找树。
比如要查找T中在区间[A,B]内的数的个数,那么结果就是lower(B)-lower(A-1);
预处理出范围内的所有perfect power和范围内的所有卡特兰数。二分搜索个数。
注意到x和y都是大于1的。而题目的范围是10^10,那么只要枚举x到10^5多一点即可。
然后算了一下每个数之多只要算30次左右就行了。如此来看,暴力是完全可以选出所有的perfect power的。
对这些数排序,然后二分搜索区间AB的上下界即可。
一、在看别人代码的时候看到一个非常屌的二分。
int lower(ll x) {
if(x<T[0])return 0;
if(x>=T[T.size()-1])return T.size();
int l=0,r=T.size()-1;
int mid;
while(l<=r) {
mid=(l+r)>>1;
if(T[mid]==x)return mid+1;
if(x>T[mid])l=mid+1;
else r=mid-1;
}
return min(r,mid)+1;
}
比如要查找T中在区间[A,B]内的数的个数,那么结果就是lower(B)-lower(A-1);
二、卡特兰数。
Ci=(4*i-2)/(i+1)*Ci-1
这个题用到的卡特兰数大约有十万,要求的是卡特兰数mod1000000007(质数)。
求的时候直接模肯定是不行的,得要求逆元。
三、乘法逆元
乘法逆元。一个数a,如果存在一个数n使得a×n=1( mod p)。那么称n为a对p的乘法逆元。
存在乘法逆元的必要条件是gcd(a,p)=1;
两种简单求法。
1、由费马小定理知,n=a ^ (euler(p))-1,euler是欧拉函数值。特殊的,素数p的欧拉函数值是p-1;
2、同余,上述式子相当于求a×n+p×y=1中的n的值。用扩展欧几里得即可求得,如果结果小于0,一直加p直到为正为止。
到这里,这个题算是做完了。快速幂什么的就不提了。
#define mod 100000007
const ll maxT=11000000000LL;
ll PowMod(ll a,ll n){
if(n==1)return a;
if(n==0)return 1;
ll tmp=PowMod(a,n>>1)%mod;
tmp=(tmp*tmp)%mod;
if(n&1)tmp=(tmp*a)%mod;
return tmp;
}
vector<ll> sel;
void ini2(){
sel.clear();
for(ll i=2;i<maxn;i++){
ll tmp=i*i;
if(tmp>maxT)break;
while(tmp<=maxT){
sel.pb(tmp);
tmp*=i;
}
}
sort(sel.begin(),sel.end());
sel.erase(unique(sel.begin(),sel.end()),sel.end());
}
int upper(ll x){
int l=0,r=sel.size()-1;
int mid;
while(l<r){
mid=(l+r)>>1;
if(sel[mid]>x)r=mid;
else l=mid+1;
}
return r;
}
int lower(ll x){
int l=0,r=sel.size()-1;
int mid;
while(l<r){
mid=(l+r)>>1;
if(sel[mid]>=x)r=mid;
else l=mid+1;
}
return r;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;return a;
}
ll gcd=exgcd(b,a%b,x,y);
ll temp=x;x=y;
y=temp-(a/b)*y;
return gcd;
}
ll C[110000];
int main(){
//cout<<PowMod(3,mod)<<endl;
ini2();
memset(C,0,sizeof(C));
C[0]=0;
C[1]=1;
for(ll i=2;i<109000;i++){
ll x,y;
exgcd(i+1,mod,x,y);
C[i]=(((C[i-1]%mod)*((4*i-2)%mod))%mod*(x%mod+mod)%mod)%mod;
}
int T;
scanf("%d",&T);
for(int tt=1;tt<=T;tt++){
ll a,b;
scanf("%lld%lld",&a,&b);
int tmpa=lower(a);
int tmpb=upper(b);
ll ans=C[tmpb-tmpa];
printf("Case %d: %lld\n",tt,ans);
}
return 0;
}