2017.10.24 T3 2009
样例数据
输入
2
2 3
2 2
输出
3
2
分析:这是一道数论题
1、当a为奇数时,b一定为奇数。
a≡b(mod2)
又
a2≡1(mod4),b2≡1(mod4)⇒ab≡a(mod4),ba≡b(mod4)⇒a≡b(mod4)
这是因为b=2x+1所以说a前面的2x次方都模成了1,即
a1≡ab(mod4)
,b同理。
以此类推,
a≡b(mod4)
又
a2≡1(mod8),b2≡1(mod8)⇒ab≡a(mod8),ba≡b(mod8)⇒a≡b(mod8)
a≡b(mod8)
又
a4≡1(mod16),b4≡1(mod16)⇒ab≡a(mod16),ba≡b(mod16)⇒a≡b(mod16)...
可以得到
a≡b(mod2n)
,又1<=b<=
2n
所以b只有唯一解。
2、当a为偶数时,b一定为偶数。
b>=n时,则
ab≡0(mod2n)
,故
ba≡0(mod2n)
,可以直接求出b>=n时的个数。
ba
%
2n
=0,设b=
2k∗c
,
(2k∗c)a=2k∗a∗ca
即k*a>=n,k>=
an
,所以b要是
2⌈an⌉
的倍数就可以了。
b
<
<script type="math/tex" id="MathJax-Element-18"><</script>n,则直接暴力。
时间复杂度O(
Nloga
)。
如果打表也是可以找到奇数的情况的规律的,偶数就看造化了。
明明给了30%的档让我们直接枚举、快速幂、判断,但是都没有人能拿满……卡常数卡得也是没谁了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
int T,a,n,ans;
int mi[35];
long long ksm(long long x,long long y)
{
long long res=1;
for(;y>=1;x=x*x%mi[n],y=(y>>1))
if(y&1)
res=res*x%mi[n];
return res;
}
int main()
{
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
mi[0]=1;
for(int i=1;i<=30;++i)
mi[i]=mi[i-1]*2;
T=getint();
while(T--)
{
ans=0;
a=getint(),n=getint();
if(a%2==1)//奇数
cout<<1<<'\n';
else//偶数
{
long long x,y;
for(int i=2;i<=n;i+=2)//n以内直接暴力快速幂
{
x=ksm(a,i);
y=ksm(i,a);
if(x==y)
ans++;
}
if(n%a==0)//大于n(为什么要if、else?这只是是向上取整操作写得丑而已)
{
ans+=mi[n]/mi[n/a];//1<=b<=2^n,所以在这个范围内找2^(n/a)的倍数
ans-=n/mi[n/a];//前提是b>=n,所以在n以内的要去掉
}
else
{
ans+=mi[n]/mi[n/a+1];
ans-=n/mi[n/a+1];
}
cout<<ans<<'\n';
}
}
return 0;
}
本题结。