[HDU2879]HeHe

题目

传送门 to HDU

思路

乱推式子,然后瞎猜。首先推成

x ( x 1 ) 0 ( m o d n ) x(x-1)\equiv 0\pmod n

然后发现 x x x 1 x-1 互质,所以不难想到, n n 的所有质因数是恰属于其中一个的。

——举例,若 2 3 n 2^3|n ,则 2 3 x 2^3|x x 1 x-1 为奇数或者 2 3 ( x 1 ) 2^3|(x-1) x x 为奇数。

如何枚举?显然二者互补,且互质。于是就是满足如下条件的 p , q \langle p,q\rangle 的数量:

p q = n ,    gcd ( p , q ) = 1 pq=n,\;\gcd(p,q)=1

然后这时候我们认为

x = k 1 p ,    x 1 = k 2 q x=k_1p,\;x-1=k_2q

如何构造?明显是式子

k 1 p k 2 q = 1 k_1p-k_2q=1

此时考虑 k 1 k_1 的范围。因为 0 x = k 1 p < n = p q 0\le x=k_1p<n=pq ,所以

0 k 1 < q 0\le k_1<q

gcd ( p , q ) = 1 \gcd(p,q)=1 保证存在一个解, k 1 k_1 通解是 k 1 + r q k_1'+rq ,所以长度为 q q 的区间中,有且仅有 一个解。这个解足以构造出 x x 。所以答案就是 p , q \langle p,q\rangle 的数量。

p , q p,q 的数量是啥子呢?就是每种质因数放到左边还是右边。就是

2 c n t 2^{cnt}

c n t cnt 用欧拉筛,就结束了。

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_42101694/article/details/108371540