hdu 6189 Law of Commutation

题目链接

给定n,a, 在区间[1,2^n]求满足a^b %m =b^a %m的b的个数

直接用快速模幂从1遍历到2^n,会TL;
判断a为奇数时,答案为1,为偶数时b也偶数,遍历减去一半,还是会TL;还需要继续剪枝T…T

(1) a为奇数:
    ans=1;
(2) a为偶数:
  因为    m=2^n,m为偶数
  所以    a^b %m 结果也为偶数
  又因为  a^b %m = b^a % m
  所以    b^a %m 结果也为偶数,b也为偶数
  a为偶数           
    令a=2 * x   =>  a^b=2^b * x^b       
  i, 当b<n时直接暴力 
  ii,当b>=n时,
     (2^b * x^b) % 2^n =0  (因子取模为零)
     此时b^a % 2^n 也要为零    
     b为偶数
       令b=(2^x) * y  =>  b^a=2^(ax) * y^a
       即当 ax>=n时满足条件
         x>=n/a,b=2^x * y;
       对x限制后,只要满足x条件,无论y怎样,都可以取x=n/a,计算y个数即可
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll; 

ll power(ll a,ll b){ //快速幂 
	ll result=1;
	for(;b;b>>=1){
		if(b&1){
			result*=a;
		}
		a*=a;
	}
	return result;
}

ll quic_power(ll a,ll b,ll mod){ //快速模幂 
	ll result=1;
	for(;b;b>>=1){
		if(b&1){
			result*=a;
			result%=mod;
		}
		a*=a;
		a%=mod;
	}
	return result;
}


int main(){
	int n,a,cnt;
	while(~scanf("%d%d",&n,&a)){
		int ans=0;
		if(a&1)  //若a为奇数 
			ans=1;
		else{
			ll mod=power(2,n);  //模  b [1,m] 
		
			cnt=0;
			for(int i=2;i<=n;i+=2)  //n以内满足条件的偶数b 
				if(quic_power(a,i,mod)==quic_power(i,a,mod))
					cnt++;
			
			ll x=n/a;  //当b>n时 
			if(x*a<n)
				x++;
			ll b=power(2,x);
			
			cnt+=(mod/b-n/b); //加上b>n之后满足条件的个数 
			ans=cnt;
		} 
		printf("%d\n",ans);	
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lidengdengter/article/details/81050338
今日推荐