math
题目描述:
给定两个数字a和n,求有多少数字b满足a^b mod 2^n = b^a mod 2^n,且1<=b<=2^n
输入格式:
第一行一个整数T代表数据组数。
接下里T行,每行两个数a和n。
输出格式:
对于每组数据输出一个整数表示b的个数
数据范围:
对于30%的数据:n<=20;T<=10
对于100%的数据:1<=n<=30;1<=a<=10^9;T<=1000。
解析:
对于30%的数据,快速幂枚举。
对于100%的数据,我们有两种方法,一种是数学证明,一种是打表找规律。
我们来数学证明一下:
当a为奇数时,b一定为奇数,证:b mod 2^n = a mod 2^n
已知奇数的平方模8余1,我们可以设b=2k+1;
则a^b mod 8 = a^(2k+1) mod 8 =(a^2k * a) mod 8 = ((a^k)^2 mod 8) * (a mod 8)
因为a^k一定为奇数,所以((a^k)^2 mod 8) * (a mod 8) = 1 * a mod 8
=
a mod 8
同理证得b^a mod 8 = b mod 8,所以b mod 2^3 = a mod 2^3
已知奇数的四次方模16余1,我们可以分别设
当b=4k+1时
则a^b mod 16 =a^(4k+1) mod 16 =(a^4k * a) mod 16 = ((a^k)^4 mod 16) * (a mod 16)
因为a^k一定为奇数,所以((a^k)^4 mod 16) * (a mod 16) = 1 * a mod 16 = a mod 16
当b=4k+3时
同理得a^b mod 16 = a^3 mod 16 = (a^2 * a) mod 16 =a mod 16
同理证得b^a mod 16 = b mod 16,所以b mod 2^4 = a mod 2^4
以此类推,得b mod 2^n = a mod 2^n。又因为1<=b<=2^n,所以b要使条件满足b只有一个解
当a为偶数时,b一定为偶数
当a>=n时,显然b^a mod 2^n = 0 mod 2^n = 0
设b = 2^(n/a),则b^a = (2^(n/a))^a = 2^n,要使得b^a mod 2^n = 0,则n/a应该向上取整。因为n/a如果不能整除,那么2^(n/a)^a将会比2^n小,不能整除。
当a<n时,因为a<=30,所以可以直接用快速幂暴力枚举
时间复杂度 O(nloga)
代码:
#include <bits/stdc++.h>
using namespace std;
int t;
int a,n;
int ans,mod;
inline int ksm(long long a,long long b,long long c) //快速幂
{
int ans=1;
a=a%c;
while(b)
{
if(b&1) ans=(ans*a)%c;
b=b>>1;
a=(a*a)%c;
}
return ans;
}
int main()
{
// freopen("math.in","r",stdin);
//freopen("mat.out","w",stdout);
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&a,&n);
if(a&1) cout<<"1"<<endl;
else
{
ans=0;
int x=0;
x+=ceil((double)n/a); //ceil函数:向上取整。注意要先转为double类型
mod=1<<n;
ans=mod/(1<<x)-n/(1<<x);
for(int i=1;i<=n;i++) //这里i要取到1的原因是ceil函数是算出大于该数的最小整数
if(ksm(a,i,mod)==ksm(i,a,mod)) ans++;
cout<<ans<<endl;
}
}
return 0;
}