lightoj 1170 Counting Perfect BST

来源:互联网 发布:手机如何装修淘宝店铺 编辑:程序博客网 时间:2024/04/30 02:20
perfect power 是指可以表示成x^y(x>1,y>1)的数,给一个区间[A,B]求由这个区间的所有perfect能组成多少种不同形态的二叉查找树。

 预处理出范围内的所有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 100000007const 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;}

0 0
原创粉丝点击