P6610 - 同餘方程 題解
一道卓越得讓我五體投地的好題/ww
首先拆 CRT 是顯然的吧()。將 \(p\) 拆成若干個奇質數 \(p_i\) 的乘積,設 \(a^2+b^2\equiv x\pmod{p_i}\) 的解集 \(X_i\)(是個二元組集合喲),則從每個 \(X_i\) 中選一組出來都能用 CRT 合併成一個模 \(p\) 的解,所以答案就是 \(\prod|X_i|\)(不需要寫 CRT 喲)。
下面考慮 \(p\) 是奇質數怎麼做。容易想到換元,令 \(y=a^2,z=b^2\),設 \(f(A)=[A\text{ 是模 }p\text{ 二次剩餘噠!}]\),則答案就是 \(4\sum\limits_{y\not\equiv 0,y\not\equiv x}f(y)f(x-y)\)
由於列舉條件是 \(y\not\equiv0,y\not\equiv x\),本能地分 \(x\) 是否為 \(0\) 討論。如果等於那是比較簡單的,設 \(m=\dfrac{p-1}2\),任取原根 \(g\),設 \(y\equiv g^\alpha\),則顯然 \(-y\equiv -g^\alpha\equiv g^{m+\alpha}\)。如果 \(m\) 是偶數,那麼 \(f(y)=f(-y)\),於是 sum 列舉的有一半都是 \(1\),算出來就是 \(4\times\dfrac{p-1}2=2(p-1)\)
\(x\not\equiv0\) 乍一看感覺很離譜,覺得不可做,因為加法和二次剩餘放一塊就像世紀難題(霧水)。但注意到二次剩餘判定方法,\(f(A)=[A^{m}\equiv 1]\),這樣 \(f(A)=0\) 對應 \(A^m\equiv-1\),\(f(A)=1\) 對應 \(A^m\equiv 1\),於是有 \(f(A)=\dfrac{A^m\bmod p+1}2\)!這樣就把一個真值表達式變成了代數式!但一個問題是,要求的 \(\sum\) 是在 \(\Z\)
接下來就略顯 trivial 了。忽略 \(f(A)\) 的分母,最後乘個 \(4\) 的逆元即可。顯然
\[\sum (y^m+1)((x-y)^m+1)=\sum(y^m(x-y)^m+y^m+(x-y)^m+1) \]第四項的和顯然是 \(p-2\)。第二三項是對稱的,分別能取遍 \([1,p)\backslash \{x\}\),而 \([1,p)\) 的 \(m\) 次方一半是 \(1\) 一半是 \(-1\),總和就是 \(0\),所以取 \(-x^m\) 就行了。第一項的話,乘進去得到 \(\!\left(xy-y^2\right)^m\),除以 \(y^2\) 顯然值不變,為 \(\left(\dfrac xy-1\right)^m\)。這就比較簡單,\(\dfrac xy\) 顯然取遍 \([2,p)\),於是 \(\dfrac xy-1\) 取遍 \([1,p-2]\)。
code
int solve(int p, int x) {
if(x == 0) return (p - 1) % 4 == 0 ? 2 * p - 1 : 1;
int m = p - 1 >> 1;
int ans = p - 2;
(ans += 2 * -qpow(x, m, p)) %= p;
(ans += -qpow(p - 1, m, p)) %= p;
ans = (ans + 10 * p) * inv(4, p) % p * 4;
return ans + 4 * (qpow(x, m, p) == 1);
}
void mian() {
int p = read(), x = read();
int ans = 1;
for(int i = 2; i * i <= p; ++i) if(p % i == 0) {
ans *= solve(i, x % i);
p /= i;
} if(p > 1) ans *= solve(p, x % p);
prt(ans), pc('\n');
}