[L,R](L≤R≤2147483647,R-L≤1000000)
,請計算區間中素數的個數。
code:c++
#include <bits/stdc++.h> using namespace std; #define maxn 1000010 int n, N, x, pri[10000]; typedef long long LL; bool a[maxn]; int Eratosthenes_Sieve(int n, int pri[]) { for (int i = 2; i * i <= n; i++) if (a[i] == 0) for (int j = i << 1; j <= n; j += i) a[j] = 1; int cnt = 0; for (int i = 2; i <= n; i++) if (!a[i]) pri[cnt++] = i; return cnt; } int main() { int cnt = Eratosthenes_Sieve(50000, pri); LL L, R; scanf("%lld %lld", &L, &R); memset(a, 0, sizeof(a)); for (int i = 0; i < cnt; i++) for (LL j = max(2ll, (L - 1) / pri[i] + 1) * pri[i] ; j <= R; j += pri[i]) a[j - L] = 1; int ans = 0; for (LL i = L; i <= R; i++) if (a[i - L] == 0) ans++; printf("%d", ans); return 0; }
\[\large https://www.luogu.org/problem/P3601\]git
給定 \(l,r\) , 求 \(\large\sum \limits_{i=l}^{r} {i- \phi (i)}\)
\(1\le l\le r\le 1e12 \ ,\ r-l\le 1e6\)算法
有下列性質 :函數
對於 \(x \in Z\), 有:ui
\(\large \phi(x) = x \times \prod\limits_{i=1}^{x}{\dfrac{p_i-1}{p_i}} (p_i \mid x)\)spa
\(x\) 的一質因子 \(p_i\) 對 \(\phi (x)\) 的貢獻爲 \(\dfrac{p_i-1}{p_i}\)code
對於 一個合數\(x\) , 至多存在一個 質因子 , \(\ge \sqrt{x}\)get
則能夠篩出 \([1,\sqrt{1e12}]\) 內的質數
而後 用這些質數 對 \([l,r]\) 進行試除 ,it
若可整除 \(x\) , 則計算其對 \(\phi(x)\) 的貢獻io
如何特判 \(\ge \sqrt{x}\) 的 之多一個 質因子 \(p_{max}\)?
顯然 , \(\large p_{max} = \dfrac{x}{\prod\limits p_i^{a_i}}\)
則可 在試除時 , 對原數 \(x\) 進行操做 ,
所有試除完畢後 , 原數 \(x\) 變成 \(1\) 或者 \(p_{max}\)
此時再計算 \(p_{max}\) 的貢獻便可
#include<cstdio> #include<vector> #include<ctype.h> #define max(a,b) (a>b?a:b) #define ll long long const int MARX = 1e6+10; const ll mod = 666623333; //============================================================= ll L,R,ans,K[MARX],phi[MARX]; bool flag[MARX]; std::vector <ll> prime; //============================================================= inline ll read() { ll s=1, w=0; char ch=getchar(); for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1; for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0'; return s*w; } //============================================================= signed main() { L = read(), R = read(); for(int i = 2; i < MARX; i ++)//篩出[2,1e6]中的質數 { if(!flag[i]) prime.push_back(i); for(int j = 2; i * j < MARX; j ++) flag[i*j] = 1; } for(ll i = L; i <= R; i ++) phi[i-L] = K[i-L] = i;//初始化 for(int i = 0,size = prime.size(); i < size; i ++)//枚舉質數 for(ll j = max(2ll, (L-1) / prime[i] + 1); prime[i]*j <= R; j ++)//枚舉質數的倍數 { ll x = prime[i] * j - L; phi[x] = phi[x] / prime[i] * (prime[i]-1);//計算 貢獻 for(;K[x] % prime[i] == 0;) K[x] /= prime[i];//除去 pi } for(ll i = L; i <= R; i ++)//枚舉l~r中的數 { if(K[i-L] != 1) phi[i-L] = phi[i-L] / K[i-L] * (K[i - L] - 1);//計算 >=sqrt(x)的質因子的貢獻 ans = (ans + (i - phi[i-L])) % mod;//累加答案 } printf("%lld", ans); }
\[\large http://uoj.ac/problem/48\]
定義: \(sgcd(x,y)\) 爲 \(x,y\) 的 次大 公約數 ,
\(ps\) : 當 \(\gcd(x,y) = 1\) 時 , \(sgcd(x,y) = -1\)
給定 一數列 \(a\) ,
求: \(sgcd(a_1,a_1),sgcd(a_1,a_2),\dots,sgcd(a_1,a_n)\)
\(n\le 1e5, a_i\le 1e12\)
有: \(\large x = \prod\limits{p_i^{a_i}}\ ,\ y = \prod\limits{p_i^{b_i}}\ ,\ \gcd{(x,y)} =\prod\limits{p_i^{\min(a_i,b_i)}}\)
由於 \(\large sgcd|x , sgcd|y\) ,
顯然 , \(\large sgcd = \frac{\gcd}{\min(p_i)}\ (\text{知足 } p_i|x , p_i|y)\)
則, 若已知 \(\gcd(a_1,a_i)\) 與 \(\min(p_i) \ (\text{知足 } p_i|x , p_i|y)\) ,
便可求得 \(sgcd(a_1,a_i)\)
\(\gcd(a_1,a_i)\) 可在 \(\log(n)\) 時間內 求得 ,
如何求得 \(\min(p_i) \ (\text{知足 } p_i|x , p_i|y)\) ?
發現 \(a_1\) 對全部的 答案 都做出 貢獻.
則有 : \(p_i|a_1 \Leftrightarrow p_i|\gcd(a_1,a_i)\)
則 能夠 預處理出\(a_1\) 的全部質因子 \(p_i\) ,
並 按照升序 , 將全部 \(p_i\) 對 \(\gcd(a_1,a_i)\) 進行試除
則, 可以 整除\(\gcd(a_1,a_i)\)的 第一個\(p_i\) , 即爲所求的 \(\min(p_i)\)
以上算法 , 極限複雜度爲 \(\Theta(\sqrt{a_1} +n(\log{n}+k))\) ,
通常 跑不滿 , 穩過 .
//知識點:數論 ,質因數分解 /* By:Luckyblock 1A開心 分析題意: */ #include<cstdio> #include<ctype.h> #include<vector> #define int long long const int MARX = 1e5+10; //============================================================= int n,a1,ax; std:: vector <int> prime;//質因數分解 a1 //============================================================= inline int read() { int s=1, w=0; char ch=getchar(); for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1; for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0'; return s*w; } int gcd(int a,int b) {return b?gcd(b,a%b):a;}//求 最大公約數 void split(int x)//質因數分解 { for(int i=2; i*i <=x; i++) { if(x%i == 0) prime.push_back(i); while(x%i == 0) x /= i; } if(x != 1) prime.push_back(x); } //============================================================= signed main() { n = read(); a1 = read(); split(a1); printf("%lld ",a1/prime[0]);//sgcd(a1,a1) for(int i=2; i<=n; i++) { ax = read(); int d = gcd(a1,ax); if(d == 1) {printf("-1 "); continue;}//無sgcd for(int j=0,size=prime.size(); j<size; j++)//枚舉每個 a1的 質因子 if(d % prime[j] == 0)//進行試除 { printf("%lld ",d/prime[j]); //輸出sgcd break; } } }
\[\large https://www.luogu.org/problem/P4167\]
給定 \(\large n\) , 求 \(\large \dfrac{1}{x} + \dfrac{1}{y} = \dfrac{1}{n!}\) 的正整數解 的對數
首先對 求解式進行轉化 :
\[\large \dfrac{1}{x} + \dfrac{1}{y} = \dfrac{1}{n!}\]
\[\large y\times n!+x\times n! = x\times y\]
\[\large x\times y - \large y\times n!-x\times n! = 0\]
\[\large x\times y - \large y\times n!-x\times n! + (n!)^2 = (n!)^2\]
根據 十字相乘法則 , 進行因式分解, 則有:
\[\large (x-n!)(y-n!) = n!\]
因爲 \(x,y,n \in Z\) , 則 \((x-n!) \text{與} (y-n!)\) 都爲 \(n!\) 的約數
則 題目所求解的對數 , 即爲 \(n!\) 的約數個數
根據 惟一分解定理 ,若設:
\[\large n! = \prod\limits{p_i^{c_i}}(p_i\mid n)\]
根據約數和定理 , 則有:
\[\large \alpha(n!) = \prod\limits{(c_i+1)}\]
則題目所求 即爲:
\[\large \alpha((n!)^2) = \prod\limits{(2\times c_i+1)}\]
因爲 \(\large n!\) 的質因子都 \(\large\le n\) ,
則能夠使用篩法直接預處理出全部 有貢獻的素數
有一公式 :
對於 \(\large n!\) , \(\large p_i\) 在 \(\large n!\) 的質因數分解中 , 指數 的值 \(\large c_i\)
\[\large c_i = \sum\limits_{k=1}^{\inf}{\lfloor\frac{n}{p_i^k}\rfloor} (p_i^k\le n)\]
根據 此公式 , 便可可求得 指數 \(c_i\) 的值
#include<cstdio> #include<vector> #include<ctype.h> #define ll long long const ll mod = 1e9+7; const int MARX = 1e6+10; //============================================================= int n; ll ans = 1; bool flag[MARX]; std::vector <ll> prime; //============================================================= inline int read() { int s=1, w=0; char ch=getchar(); for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1; for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0'; return s*w; } //============================================================= signed main() { n = read(); for(int i = 2; i <= n; i ++) //埃氏篩預處理全部 <=n的素數 { if(!flag[i]) prime.push_back(i); for(int j = 2; i * j <= n; j ++) flag[i*j] = 1; } for(int i = 0,size = prime.size(); i < size && prime[i] <= n; i ++)//枚舉素數 { ll tmp = 0, x = n, y = prime[i]; for (; x; x /= prime[i]) tmp += x / y;//求得 x/y, x/(y^2), x/(y^3)... ans = (ans * (tmp << 1 | 1) % mod) % mod;//累乘 計算貢獻 } printf("%lld",ans); }
\[\large https://www.luogu.org/problem/P2312\]
對於一個多項式 \(f(x)\) ,
\(f(x+p) \equiv f(x) \pmod{p}\)
則 若 \(f(x) = 0\), 有 \(f(x)\%p =0\)
能夠使用 取模的方法 判斷是否爲 \(0\)