Law of Commutation HDU - 6189

2018TYUT暑期ACM模拟赛(1)
Law of Commutation HDU - 6189

题意:给你n,a。m=2^n,b=[1,m], 求有多少满足a^b=b^a%m;
思路:模拟赛的当场只是听队友说了这题没有写。赛后再写。数学方面的问题啊。首先打表看了一下规律,n<=1 无论a是啥答案都是1,a为奇数的时候答案都为1 。这个肯定是能推导出来的但是我没有推。然后看打表的规律也是看不出来个啥,然后看了大佬题解,对公式的推导。
主要是:当a为偶数的时候。
1、a^b=(2^x*y)^b=2^bx*y^b ,当b大于n的时候 2^bx%m=0,即a^b%m=0,b^a%m=0.
2、a为偶数很容易看出要满足条件b肯定也为偶数。b^a=(2^x*y)^a=(2^ax*y^a)%m=(2^ax*y^a)%2^n。即只要ax>=n。就可。这样就能找出最小的x。接下来就好求了。可以找到最小的满足要求的b=(2^x*y)(y=1).然后看[1-m].有多少个满足倍数条件的b,之后再减去[1-n]内满足条件的个数。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
ll my_pow(ll a,ll n)
{
    ll ans=1;
    while(n){
        if(n&1) ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
ll quik_pow(ll a,ll n,ll mod)
{
    ll ans=1;
    while(n){
        if(n&1)
            ans=ans*a,ans%=mod;
        a=a*a;
        a%=mod;
        n>>=1;
    }
    return ans;
}

int main()
{
    ll n,a;
    while(cin>>n>>a){
        ll m=1<<n;
        if(n<=1){//n=1都为1
            cout<<1<<endl;
            continue;
        }
        else if(a&1){//n无论为啥只要,a只要是奇数就为1
            cout<<1<<endl;
            continue;
        }
        else{
            ll cnt=0;
            for(int i=1;i<=n;i++){//小于n的直接暴力求解
                if(quik_pow(a,i,m)==quik_pow(i,a,m))
                    cnt++;
            }
            ll x=n/a;//b^a=2^ax。min x
            if(x*a<n) x+=1.;
            ll tmp=my_pow(2,x);
            x=m/tmp-n/tmp;
            cnt=cnt+x;//减去n中tmp的倍数
            cout<<cnt<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/miranda_ymz/article/details/81050799