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