记不太清楚了 - - 按着当时比赛的思路写吧……
先把 a a a 拆开表示成 a = 2 q ∗ k a=2^q*k a=2q∗k,然后考虑 a x % 2 p = ( 2 q ∗ k ) x % 2 p = ( 2 q ∗ x ∗ k x ) % 2 p a^x\%2^p=(2^q*k)^x\%2^p=(2^{q*x}*k^x)\%2^p ax%2p=(2q∗k)x%2p=(2q∗x∗kx)%2p,那么我们可以分情况讨论一下。
第一种情况, ( 2 q ∗ x ∗ k x ) % 2 p = 0 (2^{q*x}*k^x)\%2^p=0 (2q∗x∗kx)%2p=0 即 p ≤ q ∗ x p \leq q*x p≤q∗x, ⌈ p q ⌉ ≤ x \lceil \frac{p}{q} \rceil \leq x ⌈qp⌉≤x,此时 x a % 2 p = 0 x^a\%2^p=0 xa%2p=0 也是成立的,设 x = 2 m ∗ l x=2^m*l x=2m∗l 那么就是要有 2 p ≤ 2 m ∗ a 2^p \leq 2^{m*a} 2p≤2m∗a 即 ⌈ p a ⌉ ≤ m \lceil \frac {p}{a} \rceil\leq m ⌈ap⌉≤m,因为要求出所有满足题意的 x x x 的个数,那么 m m m 取最小 ⌈ p a ⌉ \lceil \frac {p}{a} \rceil ⌈ap⌉,根据 x x x 的取值范围 [ 1 , 2 p ] [1,2^p] [1,2p] 还有刚才求出来的 ⌈ p q ⌉ ≤ x \lceil \frac{p}{q} \rceil \leq x ⌈qp⌉≤x 可以知道 x x x 取 [ ⌈ p q ⌉ , 2 p ] [\lceil \frac{p}{q} \rceil, 2^p] [⌈qp⌉,2p] 中所有 2 m 2^m 2m 的倍数,这一部分的答案个数就是 2 p 2 m − ⌈ p q ⌉ 2 m + [ ⌈ p q ⌉ % 2 m = = 0 ] \frac {2^p}{2^m}-\frac {\lceil \frac{p}{q} \rceil}{2^m}+[\lceil \frac{p}{q} \rceil\%2^m==0] 2m2p−2m⌈qp⌉+[⌈qp⌉%2m==0]。
第二部分是 ( 2 q ∗ x ∗ k x ) % 2 p ! = 0 (2^{q*x}*k^x)\%2^p !=0 (2q∗x∗kx)%2p!=0 即 x ∗ q < p x*q < p x∗q<p,由于 p p p 很小直接 for 循环特判 a x % 2 p a^x\%2^p ax%2p 和 x a % 2 p x^a\%2^p xa%2p 即可。
代码
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 31;
ll ar[maxn];
void init ()
{
ar[0] = 1;
for (int i = 1; i < maxn; ++i) {
ar[i] = 2*ar[i-1];
}
}
ll qm (ll a, ll b, ll mod)
{
ll res = 1;
while (b) {
if (b&1) {
res = res*a%mod;
}
a = a*a%mod;
b >>= 1;
}
return res;
}
int main ()
{
init();
int t, a, p;
scanf("%d", &t);
while (t--) {
scanf("%d %d", &a, &p);
int q = 0, v = a;
while (v % 2 == 0) {
v /= 2;
++q;
}
if (q == 0) {
cout << 1 << '\n';
continue;
}
int bgn = (p%q)?p/q+1:p/q;
int tmp = (p%a)?p/a+1:p/a;;
ll res = ar[p]/ar[tmp]-bgn/ar[tmp]+(bgn%ar[tmp]==0);
for (int x = 1; x*q < p; ++x) {
if (qm(a, x, ar[p]) == qm(x, a, ar[p])) {
++res;
}
}
cout << res << '\n';
}
return 0;
}