当时省赛花了很长时间在这道题上,最后也没做出来,特别伤心啊啊啊啊赛后仔细研究了一下,怎么说呢,学到了很多,也认识到了自己的不足,唉…
Little Sub has just received an equation, which is shown below, as his birthday gift. a^x ≡ x^a(mod 2^p).
Given the value of a, please help Little Sub count the number of x (1<=x<=2^p)which satisfies the equation.
There are multiple test cases. The first line of the input contains an integer T about(1000), indicating the number of test cases. For each test case:
The first and only line contains two integers :a and p (1<=a<=1e9,1<=p<=30).
For each test case output one line containing one integer, indicating the answer.
2
6 12
8 16
1023
16383
话不多说,上代码吧,代码说实话写的有点乱,将就看一下吧
#include
#include
#include
#include
#include
using namespace std;
int main()
{
long long kk,a,p,n,i,ans,sum,c,o,e,s1,s2,a1,a2;//变量定义的有点多哈
int t;
scanf("%d",&t);
while( t-- )
{
kk=0;
scanf("%lld %lld",&a,&p);
if(a%2!=0) //做之前用快速幂手动打的表,发现当a为奇数时x个数必为1
{printf("1\n");
continue;}
if(p==1) //当p为1时,x的个数必为1
{printf("1\n");
continue;}
if(p==2) //当p为2时,x的个数必为2
{printf("2\n");
continue;}
/*以上特判是打表发现的*/
ans=0;sum=1; //sum为2的p次方
c=2; //c为基数2
int pl=p; //在这里用pl来记录p!很重要哈,pl就是p,别看到后面不知道pl是啥
while(p>0) //这里用计算2的p次方记为sum
{
if(p%2==1)
{sum=sum*c;}
c=c*c;
p=p>>1;
}
for(i=1;i<pl;i++) //因为现在只考虑a是偶数的情况,所以a是2的倍数
{ //现在考虑恒等式前面的式子即a^x
//所以当x大于p的时候,a^x模2^p一定是0!!!
//因为p是小于30,可以暴力解出x小于p时的个数
s1=s2=1; //s1和s2分别为前后两个式子的得数
o=i;e=a; //o相当于第一的式子的x,e相当于第二个式子的a
a1=a,a2=i; //a1,a2分别相当于前后两个式子的底数
while(o>0) //在这里用了两次快速幂来计算
{
if(o%2==1)
{
s1=s1%sum;
a1=a1%sum;
s1=s1*a1;
}
a1=a1%sum;
a1=a1*a1;
o=o>>1;
}
s1=s1%sum;
while(e>0)
{
if(e%2==1)
{
s2=s2%sum;
a2=a2%sum;
s2=s2*a2;
}
a2=a2%sum;
a2=a2*a2;
e=e>>1;
}
s2=s2%sum;
if(s2==s1)
{
kk=kk+1; //如果两边相等则kk+1
}
}
//前面说过,当x大于p时,左面的的式子结果必为0,
//所以就判断右面的式子模2^p是否为0就行了
if(a>=pl)//这里我分了两种情况,当a>=pl时,只要求出在pl到2^p之间2的倍数的个数就行啦
{
if(pl%2==0)
{
ans=(sum-pl)/2+1;
}
if(pl%2!=0)
{
pl=pl+1;
ans=(sum-pl)/2+1;
}
}
if(a<pl)//当a
{
int op=1;//在这里我们因为要求出x^a模2^p为0的个数上面指数为恒为a,变得只是x
while(op*a<pl)//因此我们求2的几次方*a次方(指数*a)比pl大,以此来确保模为0!!仔细理解一下这段话哈
{op++;}
c=2;
long long sum1=1;//在这里再算一下2的op次方
while(op>0)
{
if(op%2==1)
{sum1=sum1*c;}
c=c*c;
op=op>>1;
}
if(pl%sum1==0) //以下是判断从哪个区间开始查找个数,仔细研究一下
{
ans=(sum-pl)/sum1+1;
}
if(pl%sum1!=0)
{
int oo=1;
while(oo*sum1<pl)
{
oo++;
}
pl=oo*sum1;
ans=(sum-pl)/sum1+1;
}
}
ans=ans+kk;//最后别忘了之前求的当x小于pl时的情况,记得加上kk哦
printf("%lld\n",ans);
}
return 0;
}
输入理想的程序,输出快乐的人生
此中有真意
欲辨已忘言
共勉!