Time Limit : 1 Second Memory Limit : 65536 KB
Source : 第十届山东省ACM省赛
Problem Link : ZOJ 4123
Author : Houge Date : 2019-5-24
看了快一周的k题,看了好多题解,还是不明白,只恨自己不是数论大佬。昨天看了本校数竞大佬Ch_3225的题解,感觉还不错,和我目前看过的都不太一样(但还是看不懂)。征得同意后,这里就直接copy上来了。
(注意:在此篇题解中,为码字方便,记a^b为a的b次方,而不是c语言定义的异或运算。优先级以幂的运算优先级为准。)
(“|”符号为整除符号,即右边的数➗左边的数得到整数)
题目大意:
即求x∈{1,2,.....,2^p}使得a^x≡x^a(mod 2^p)。
分析:
要求式为了找到x的个数,我们考虑什么样的x满足上述方程。
·变形,原式即为2^p|abs(a^x-x^a)。 (①式)
·记abs(a^x-x^a)为R。
我们考虑a^x-x^a的2的幂次。为了从右式通过提取因子提出尽可能多的2,我们设:
·a=a0*2^i;
·x=x0*2^j;
其中a0和x0都是奇数。
于是代入①式,2^p|abs((a0*2^i)^(x0*2^j)-(x0*2^j)^(a0*2^i))
于是 R=2^(min((i*x0*2^j),(j*a0*2^i)))*p;(x!=a)(p是某个奇数)
或 R=0;(x==a)
即 R=2^(min((i*x),(j*a)))*p;(x!=a)(p是某个奇数)
或 R=0;(x==a)
当x!=a的时候,我们想要使x满足该方程,需要
2^p|2^(min((i*x),(j*a)))*p;(p是某个奇数)
即 p<=min(i*x,j*a)
即 i*x>=p且j*a>=p ②式
因为我们要找的是合法的x,并且我们设的j也和x有关,于是我们将上式变形:
x>=⌈p/i⌉且j>=⌈p/a⌉
这两个式子是说,x(提醒一下x!=a,x==a一会再另算)要满足要求式必须是在[⌈p/x⌉,2^p]区间内并且被2^⌈p/a⌉整除的整数.
值得注意的是,如果i=0,即a为奇数,我们回到式②,发现i*x不可能大于等于②,从而没有x!=a满足要求式。对于这种特殊的情况,可以设下边说的那个X在这种情况下为0。
这样想想,这个问题变成了求一个区间里有多少个某个数的倍数这种问题,就比较显然了。
满足条件的x!=a的x有X=(2^p/2^⌈p/a⌉-(⌈(p+i-1)/i⌉-1)/2^⌈p/a⌉)个。
当然,对于x==a的情况,我们单独算一下,是不是已经满足式X,或者不符合x在定义域内的要求。
如果x符合在定义域内的要求并且不满足式②的话,那么Y=1;否则Y=0。
我们要求的数就是X+Y了。计算输出它即可。
代码:
1 #include2 using namespace std; 3 long long pingfanmi(long long a,long long b) 4 { 5 long long d=b,sum=1; 6 while(d--)sum*=a; 7 return sum; 8 } 9 int main() 10 { 11 int T; 12 long long a,i,p,temp,s,r,sum; 13 scanf("%d",&T); 14 while(T--) 15 { 16 sum=0; 17 scanf("%lld%lld",&a,&p); 18 s=pingfanmi(2,p); 19 r=pingfanmi(2,(p+a-1)/a); 20 temp=a; 21 for(i=0;temp%2==0;i++,temp/=2); 22 if(i==0) 23 { 24 printf("1\n"); 25 continue; 26 } 27 sum=(s/r-((p+i-1)/i-1)/r); 28 if(a%r==0&&a ; 29 printf("%lld\n",sum); 30 } 31 return 0; 32 } 33 //别问我为什么没用快速幂,我懒