EOJ Monthly 2019.5 (based on May Selection) B.幂运算

 

在这里插入图片描述
在这里插入图片描述
这题是一道不容易写的数学题,并且题目只给了1s,就是说O(n)的算法都会T(我T了无数发),这时我们就要从别的方向考虑了。

我们发现a,b,c,d都是在1e9范围内的,就是说如果我们把a和c看成x ^ k1和x ^ k2,那么k1,k2<=32,这下子我们的运算量一下就小下来了。
题目要求的是a ^ b = c ^ d,我们把a,c按照上面那样处理,变成x ^ k1和x ^ k2,这样最后的式子就是x ^ (k1b)= x ^ (k2d)——>k1b = k2d。

最后答案由两部分组成:
平凡的情况:a=c,b=d 。
其他的情况:a≠c,就必须满足 k1 * b = k2 * d,为保证不重复计数,我们必须满足gcd(k1,k2)=1,然后我们跑两个(1,32)的 for 循环,再对每个满足条件的答案进行处理,这题也就不那么难了。

我这种做法的时间复杂度大概是O(32 * 32 * log n),但是好像别人有O(2 * 32 * log n)
的做法……

#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
#define ll long long

const ll mod=1e9+7;
ll a,b,c,d;

ll poww(ll a,ll b){
    ll ans=1,base=a;
    while(b!=0){
        if(b&1!=0)ans=ans*base;
        base=base*base;
        b>>=1;
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
        ll ans=b*d;
        for(int i=1;i<=32;i++)
            for(int j=1;j<=32;j++){
                if(__gcd(i,j)!=1)continue;
                ll A=pow(a,1.0/i);
                ll C=pow(c,1.0/j);
                while(poww(A,i)<=a)
                    A++;
                while(poww(C,j)<=c)
                    C++;
                A--;C--;
                ans+=min(A-1,C-1)*min(b/j,d/i);
                ans%=mod;
            }
        printf("%lld\n",ans);
    }
    return 0;
} 

 

posted @ 2019-05-31 20:05  Mmasker  阅读(100)  评论(0编辑  收藏  举报