1. 程式人生 > >loj Snakes 的 Naïve Graph 【數論】

loj Snakes 的 Naïve Graph 【數論】

int mat bin con 表示 開始 res include ref

題目鏈接

loj

題解

感謝珂神的指導orz

觀察式子\(i \times j \equiv 1 \pmod m\),顯然\(i,j\)是模\(m\)意義下成對的逆元,只需統計模\(m\)意義下存在逆元的數的個數,即與\(m\)互質的數的個數\(\varphi(m)\)
每對逆元的連邊有兩種情況,記逆元對數為\(x\),則方案數為\(2^x\)

真的完了嗎?難點才剛開始
\(m\)意義下有的數逆元為本身!此時不能計入答案
所以我們還需求模\(m\)意義下逆元為本身的數的個數

重新理解一下中國剩余定理,本質是環同構
\(m = a_1a_2a_3\dots\)
其中\(a_i = p_i^{k_i}\)


那麽首先在模\(a_i\)意義下分別有一個整環
我們把這些整環放在一起,用向量表示,成一個新環,可與模\(m\)意義下的整環一一對應,即環同構
例如\(Z/6 = Z/2 \centerdot Z/3\)
則對應關系
0 (0,0)
1 (1,1)
2 (0,2)
3 (1,0)
4 (0,1)
5 (1,2)

環同樣滿足加減乘
所以我們需要求出在模每個\(a_i\)下平方等於\(1\)的數的個數,乘起來即可
\[ \begin{aligned} x^2 \equiv 1 \pmod m \(x + 1)(x - 1) \equiv 0 \pmod m \end{aligned} \]

所以我們只需\((x + 1)(x - 1)\)

\(m\)的倍數即可
對於\(p > 2\)\(p\)不能同時整除\((x + 1)\)\((x - 1)\),所以只能一者為\(0\),所以有兩種方案
對於\(p = 2\)\((x + 1)(x - 1)\)必須都是偶數,顯然有一個不能整除\(4\),所以另一個應能整除\(2^{k-1}\),或者兩個如\(p > 2\)的情況,有一者為\(0\),但是\(k \le 2\)時會重復,所以特判一下,\(k = 1\)\(1\)\(k = 2\)\(2\),否則為\(4\)
以上線篩處理即可

#include<algorithm>
#include<iostream>
#include<cstring> #include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int #define res register using namespace std; const int maxn = 10000005,maxm = 100005,INF = 1000000000,P = 311021; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } int p[maxn],pi,isn[maxn],phi[maxn],N = 10000000; int f[maxn],bin[maxn],tw[maxn],tot[maxn],all[maxn]; void init(){ phi[1] = 1; for (res int i = 2; i <= N; i++){ if (!isn[i]){ p[++pi] = i,phi[i] = i - 1; if (i == 2) tw[i] = 1; else tot[i] = 1; } for (res int j = 1; j <= pi && i * p[j] <= N; j++){ isn[i * p[j]] = true; if (i % p[j] == 0){ phi[i * p[j]] = phi[i] * p[j]; if (p[j] == 2){ tw[i * p[j]] = tw[i] + 1; tot[i * p[j]] = tot[i]; } else{ tw[i * p[j]] = tw[i]; tot[i * p[j]] = tot[i]; } break; } phi[i * p[j]] = phi[i] * (p[j] - 1); if (p[j] == 2){ tot[i * p[j]] = tot[i]; tw[i * p[j]] = tw[i] + 1; } else{ tot[i * p[j]] = tot[i] + 1; tw[i * p[j]] = tw[i]; } } } bin[0] = 1; for (res int i = 1; i <= N; i++) bin[i] = (bin[i - 1] << 1),bin[i] >= P ? (bin[i] -= P) : 0; for (res int i = 1; i <= N; i++){ all[i] = bin[tot[i]]; if (tw[i] == 2) all[i] = all[i] * 2 % P; else if (tw[i] > 2) all[i] = all[i] * 4 % P; } for (res int i = 1; i <= N; i++){ f[i] = f[i - 1] + bin[(phi[i] - all[i]) >> 1],f[i] >= P ? (f[i] -= P) : 0; } } int c[maxn],ci; int main(){ init(); int q = read(),l,r; while (q--){ l = read(); r = read(); printf("%d\n",(f[r] - f[l - 1] + P) % P); } return 0; }

loj Snakes 的 Naïve Graph 【數論】