[HDU2879]HeHe

tech2022-08-08  149

题目

传送门 to HDU

思路

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

x ( x − 1 ) ≡ 0 ( m o d n ) x(x-1)\equiv 0\pmod n x(x1)0(modn)

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

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

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

p q = n ,    gcd ⁡ ( p , q ) = 1 pq=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 x=k1p,x1=k2q

如何构造?明显是式子

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

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

0 ≤ k 1 < q 0\le k_1<q 0k1<q

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

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

2 c n t 2^{cnt} 2cnt

c n t cnt 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; }
最新回复(0)