题目
思路
乱推式子,然后瞎猜。首先推成
然后发现 和 互质,所以不难想到, 的所有质因数是恰属于其中一个的。
——举例,若 ,则 且 为奇数或者 且 为奇数。
如何枚举?显然二者互补,且互质。于是就是满足如下条件的 的数量:
然后这时候我们认为
如何构造?明显是式子
此时考虑 的范围。因为 ,所以
而 保证存在一个解, 通解是 ,所以长度为 的区间中,有且仅有 一个解。这个解足以构造出 。所以答案就是 的数量。
而 的数量是啥子呢?就是每种质因数放到左边还是右边。就是
用欧拉筛,就结束了。
代码
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int_;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
const int MaxN = 10000005;
int cnt[MaxN];
bool isPrime[MaxN];
vector< int > primes;
void sieve(int n){
for(int i=2; i<=n; ++i)
isPrime[i] = true;
for(int i=2,len=0; i<=n; ++i){
if(isPrime[i]){
++ len, cnt[i] = 1;
primes.push_back(i);
}
for(int j=0; j<len; ++j){
if(primes[j] > n/i) break;
isPrime[primes[j]*i] = 0;
cnt[primes[j]*i] = cnt[i]+1;
if(i%primes[j] == 0){
-- cnt[primes[j]*i];
break; // 强有力的剪枝
}
}
}
}
int qkpow(int_ bas,int q,int Mod){
int ans = 1;
for(; q; q>>=1,bas=bas*bas%Mod)
if(q&1) ans = ans*bas%Mod;
return ans;
}
int main(){
sieve(MaxN-5);
for(int i=2; i<=MaxN-5; ++i)
cnt[i] += cnt[i-1];
int n, m; scanf("%*d");
while(~scanf("%d",&n)){
scanf("%d",&m);
printf("%d\n",qkpow(2,cnt[n],m));
}
return 0;
}