题目描述:
题目大意:
给定a,n(a≤
109
,n≤30),求有多少b(1≤b≤
2n
)满足:
ab≡ba(mod2n)
。多组数据。
样例输入
2
2 3
2 2
样例输出
3
2
题目分析
找规律加数学推理。首先分两种情况:
a为奇数:如果你打了个暴力,然后打打表什么的就可以发现答案恒为1。证明如下:
1、a为奇数,b也一定为奇数,否则,
ab
和
ba
的奇偶性不同,就不可能同余
2n
。
2、再证明
b≡a(mod2n)
,利用数学归纳。
①奇数平方模8余1(你可以写成
(2n+1)2
展开就能证明),所以有
ab≡a(mod8)
, 证明
⇒
ab%8
⇒
a2k∗a1%8
(假设b=2k+1)
⇒
(ak)2∗a%8
⇒
1*a%8,即
ab≡a(mod8)
,同理
ba≡b(mod8)
,又因为题目中要求的是
ab≡ba(mod2n)
,那么可得
ab≡ba(mod8)
(此步证明见最后),于是再综合前面两个得
a≡b(mod8)
。
②奇数四次方模16余1,所以有
ab≡ab%4(mod16)
, 证明
⇒
ab%16
⇒
a4k∗
ab%4%16
(令b=4k+b%4)
⇒
(ak)4∗ab%4%16
⇒
1∗ab%4%16
,即
ab≡ab%4(mod16)
,同理
ba≡ba%4(mod16)
,又因为题目中要求的是
ab≡ba(mod2n)
,那么可得
ab≡ba(mod16)
,那么综合前面的可得
ab%4≡ba%4(mod16)
,又因为
ab≡ba(mod2n)
,那么可得
ab≡ba(mod4)
,于是得
a≡b(mod4)
,即a%4=b%4,所以得到
a≡b(mod16)
。
③同理我们可得
⇒
a≡b(mod32)
3、于是归纳得出满足要求的a,b满足条件
b≡a(mod2n)
,又因为a,n确定,且1≤b≤
2n
,那么b就是唯一确定,即答案为1。
a为偶数:
1、同理b也一定为偶数。
2、若n≤b,则
ab≡0(mod2n)
,因为题目要求
ab≡ba(mod2n)
,故
ba≡0(mod2n)
。再设b=
2k∗c
⇒
(2k∗c)a≡2ka∗ca≡0(mod2n)
,于是得n≤a*k
⇒
⌈
na
⌉
≤k(向上取整),即
2⌈na⌉
整除
2k
⇒
2⌈na⌉
整除b,因为1≤b≤
2n
,所以n≤b的范围内,符合要求的b个数就是看
2n
内有多少个
2⌈na⌉
的倍数,即
2n
/
2⌈na⌉
(如果
2⌈na⌉
小于n,还需减去n以内
2⌈na⌉
的倍数的个数,即n/
2⌈na⌉
)。
3、若
b<n
,因为n≤30,暴力枚举加判断就行。
PS: 证明
ab≡ba(mod2n)
可推得
⇒
ab≡ba(mod2k)
(
k<n
),
ab≡ba(mod2n)
⇒
ab=ba+2n∗x
⇒
ab=ba+2k∗m
⇒
ab≡ba(mod2k)
。
附代码
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
#include<queue>
using namespace std;
int mi[50],t,n,a,ans,x;
int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
int ksm(int x,int y)
{
int ret=1;
for(;y;y/=2,x=(long long)(x*x)%mi[n])
if(y&1) ret=(long long)(ret*x)%mi[n];
return ret;
}
int main()
{
//freopen("math.in","r",stdin);
//freopen("math.out","w",stdout);
mi[0]=1;
for(int i=1;i<=30;i++)//预处理2的次幂
mi[i]=(mi[i-1]<<1);
t=readint();
while(t--)
{
a=readint();n=readint();
if(a%2==1) printf("1\n");
else
{
ans=0;
x=(n+a-1)/a;//相当于向上取整
ans+=mi[n]/mi[x];
ans-=n/mi[x];
for(int i=2;i<=n;i+=2)
if(ksm(a,i)==ksm(i,a)) ans++;
printf("%d\n",ans);
}
}
return 0;
}