莫比乌斯反演 学习笔记
一、前置技能
- 积性函数
定义\(f(n)\)是积性函数,如果满足\(f(nm)=f(n)f(m), gcd(n,m) = 1\)
\(f(n)\)称为完全积性函数,当且仅当满足\(f(nm) = f(n)f(m), n,m\in Z\)
数论函数\(f(n)\)是积性函数的充分必要条件是:
\(f(1) = 1\) 且 \(f(n) = f(p_1^{a_1})f(p_2^{a_2})\cdots f(p_s^{a_s})\)
数论函数\(f(n)\)是完全积性函数的充分必要条件是:
\(f(1) = 1\) 且 \(f(n) = f^{a_1}(p_1)f^{a_2}(p_2) \cdots f^{a_s}(p_s)\)
若\(f(x)\)和\(g(x)\)是积性函数则:
- \(h(x) = f(x^p)\)
- \(h(x) = f^p(x)\)
- \(h(x) = f(x)g(x)\)
- \(h(x) = \sum_{d|x}f(d)g(\frac{x}{d})\)
也是是积性函数
- 常用数论函数
- 单位函数:\(\epsilon(n)=[n=1]\)(当且仅当\(n=1\)时值为\(1\),其他情况值为\(0\))
- 恒等函数:\(ID(n) = n\)(就是自身)
- 常数函数:\(1(n) = 1\)(都是\(1\))
- 除数函数:\(d(n) = (a_1+1)\cdots(a_s+1)\)(其中\(n=\prod_{i=1}^{s}p_i^{a_i}\),表示\(n\)的因子数量)
- 欧拉函数:\(\phi(n) = \sum_{i=1}^{n}[gcd(i,n)=1]\)(欧拉函数表示\(1\)到\(n\)之间和\(n\)的最大公约数为\(1\)的数的数量)
- 莫比乌斯函数:\(\mu(n) = \begin{cases} 1 & n=1 \\ 0 & \exists p > 1\ and\ p^2|n \\ (-1)^{\omega(n)} & otherwise\end{cases}\)
(\(\omega(n)\)表示\(n\)的不同质因子数量,\(p\)为素因子)
-
\(Dirichlet\)卷积
\((f*g)(n) = \sum_{d|n}f(d)g(\frac{n}{d})\)
\(Dirichlet\)卷积满足交换律和结合律
\(\epsilon 为Dirichlet卷积单位元,满足f*\epsilon = f\) -
常用\(Dirichlet\)卷积函数
- \(\epsilon = \mu * 1 \Leftrightarrow \epsilon(n) = \sum_{d|n}\mu(d)\)
- \(f = f * \epsilon \Leftrightarrow f(n) = \sum_{d|n}f(d)\cdot \epsilon(\frac{n}{d})\)(任意函数\(f\)和单位函数卷积都为自身,因为单位函数只有在等于\(1\)的时候才是\(1\))
- \(\phi = \mu * id \Leftrightarrow \phi(n) = \sum_{d|n}d\cdot \mu(\frac{n}{d})\)
- \(id = \phi * 1 \Leftrightarrow n = \sum_{d|n}\phi(d)\)
- \(d = 1 * 1 \Leftrightarrow d(n) = \sum_{d|n} 1\)
- \(\frac{\phi(n)}{n} = \frac{\mu(n)}{n} * 1 \Leftrightarrow \sum_{d|n}\frac{\mu(d)}{d} \cdot \frac{n}{d}\)
- 关于整除
- \(\lfloor\frac{n}{a\cdot b} \rfloor = \lfloor\frac{\lfloor\frac{n}{a} \rfloor}{b} \rfloor\)
证明:
- 数论分块:对于任意\(i\le n\),最大的满足\(\lfloor \frac ni \rfloor =\lfloor \frac nj\rfloor\)的\(j=\lfloor\frac{n}{\lfloor\frac ni \rfloor}\rfloor\)
证明:
二、莫比乌斯函数
定义莫比乌斯函数为:\(\mu(n) = \begin{cases}1 & n = 1 \\ 0 & \exists\ p>1\ and\ p^2|n \\ (-1)^{\omega(n)} & otherwise \end{cases}\)
\(\omega(n)\)为\(n\)的不同的素因子数量,\(p\)为素因子
一个最基本、最重要的性质:
证明:
欧拉反演:
证明:
莫比乌斯函数是个积性函数,所以可以直接用线性筛筛出来:
view code
int mu[MAXN];
void sieve(){
vector<bool> pm(MAXN,true);
vector<int> prime;
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] <= MAXN; j++){
mu[i*prime[j]] = -mu[i];
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
}
}
}
三、莫比乌斯反演
莫比乌斯反演定理:设\(f(m),F(n)\)是数论函数,那么
成立的充分必要条件是
利用Dirichlet卷积证明
证明:
利用定义证明
充分性:
必要性:
另一形式:
证明:
充分性:
必要性
四、例题:
- LuoguP3935 Calculating🔗
题解:
数论分块来做就好了
复杂度\(O(\sqrt{r})\)
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const LL MOD = 998244353;
LL l, r;
LL solve(LL n){
LL ret = 0;
for(LL l = 1, r; l <= n; l = r + 1){
r = n / (n/l);
ret = (ret + (r-l+1) * (n/l)) % MOD;
}
return ret;
}
int main(){
____();
cin >> l >> r;
cout << (solve(r) - solve(l-1) + MOD) % MOD << endl;
return 0;
}
- LuoguP3455 [POI2007]ZAP-Queries🔗
题解:
然后处理出来莫比乌斯函数的前缀和用整除分块来做就好了
复杂度\(O(Q\sqrt{max\{\bar{a},\bar{b}\}})\)
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 5e4+7;
typedef long long int LL;
LL mu[MAXN];
void sieve(){
vector<bool> pm(MAXN,true);
vector<int> prime;
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++) mu[i] += mu[i-1];
}
void solve(){
int a,b,k;
LL ret = 0;
scanf("%d %d %d",&a,&b,&k);
a /= k, b /= k;
if(a>b) swap(a,b);
for(int l = 1, r; l <= a; l = r + 1){
r = min(a / (a / l), b / (b / l));
ret += (mu[r] - mu[l-1]) * (a/l) * (b/l);
}
printf("%lld\n",ret);
}
int main(){
int T;
sieve();
for(scanf("%d",&T); T; T--) solve();
return 0;
}
- LuoguP4450 双亲数(第二题的简化版)🔗
题解:
和上一题一样
复杂度\(O(\sqrt{max(A,B)})\)
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e6+7;
typedef long long int LL;
LL mu[MAXN];
void sieve(){
vector<bool> pm(MAXN,true);
vector<int> prime;
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++) mu[i] += mu[i-1];
}
void solve(){
int a,b,k;
LL ret = 0;
scanf("%d %d %d",&a,&b,&k);
a /= k, b /= k;
if(a>b) swap(a,b);
for(int l = 1, r; l <= a; l = r + 1){
r = min(a / (a / l), b / (b / l));
ret += (mu[r] - mu[l-1]) * (a/l) * (b/l);
}
printf("%lld\n",ret);
}
int main(){
sieve();
solve();
return 0;
}
- LuoguP2257 YY的GCD🔗
题解:
我们枚举每个质数\(p\)然后用前两题的办法来计算有多少个\(x,y\)满足\(gcd(x,y)=p\)
这样复杂度是很高的,所以得要继续推柿子
下面假设\(n\le m\)
复杂度\(O(MAXN + T\sqrt{max(n,m)})\)
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e7+7;
typedef long long int LL;
int mu[MAXN];
LL pre[MAXN];
bool pm[MAXN];
vector<int> prime;
void sieve(){
fill(begin(pm),end(pm),true);
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int p : prime) for(int i = 1; i * p < MAXN; i++) pre[i*p] += mu[i];
for(int i = 1; i < MAXN; i++) pre[i] += pre[i-1];
}
void solve(){
int n,m;
LL ret = 0;
scanf("%d %d",&n,&m);
if(n>m) swap(n,m);
for(int l = 1, r; l <= n; l = r + 1){
r = min(n/(n/l),m/(m/l));
ret += (LL)(n/l) * (m/l) * (pre[r] - pre[l-1]);
}
printf("%lld\n",ret);
}
int main(){
sieve();
int T; for(scanf("%d",&T); T; T--) solve();
return 0;
}
- LuoguP3768 简单的数学题🔗
题解:
不多BB直接开始推柿子
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const int MAXN = 5e6+7;
int phi[MAXN], prime[MAXN], cnt;
LL p,S[MAXN],inv2,inv6;
unordered_map<LL,LL> MS;
void sieve(){
phi[1] = 1;
for(int i = 2; i < MAXN; i++){
if(!phi[i]) phi[i] = i-1, prime[cnt++] = i;
for(int j = 0; i * prime[j] < MAXN; j++){
if(i%prime[j]==0){
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
phi[i*prime[j]] = phi[i] * phi[prime[j]];
}
}
for(int i = 1; i < MAXN; i++) S[i] = (S[i-1] + 1ll * i * i % p * phi[i] % p) % p;
}
LL ksm(LL a, LL b){
a %= p;
LL ret = 1;
while(b){
if(b&1) ret = ret * a % p;
b >>= 1;
a = a * a % p;
}
return ret;
}
LL inv(LL x){ return ksm(x,p-2); }
LL sum1(LL n){ n %= p; return n * (n + 1) % p * inv2 % p; }
LL sum2(LL n){ n %= p; return n * (n + 1) % p * (2 * n + 1) % p * inv6 % p; }
LL sum3(LL n){ return sum1(n) * sum1(n) % p; }
LL calS(LL n){
if(n<MAXN) return S[n];
if(MS.count(n)) return MS[n];
LL ret = sum3(n);
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
ret = (ret - calS(n / l) * (sum2(r) - sum2(l - 1) + p) % p + p ) % p;
}
return MS[n] = ret;
}
void solve(LL n){
LL ret = 0;
for(LL l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
ret = (ret + sum1(n/l) * sum1(n/l) % p * (calS(r) - calS(l-1) + p) % p) % p;
}
printf("%lld\n",ret);
}
int main(){
LL n;
scanf("%lld %lld",&p,&n);
sieve();
inv2 = inv(2), inv6 = inv(6);
solve(n);
return 0;
}
- LuoguP3172 [CQOI2015]选数🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e6+7;
typedef long long int LL;
const LL MOD = 1e9+7;
int N,K,L,H,mu[MAXN];
vector<int> prime;
bool pm[MAXN];
LL S[MAXN];
unordered_map<LL,LL> MS;
void sieve(){
mu[1] = 1;
fill(begin(pm),end(pm),true);
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++) S[i] = S[i-1] + mu[i];
}
LL ksm(LL a, LL b){
LL ret = 1;
while(b){
if(b&1) ret = ret * a % MOD;
b >>= 1;
a = a * a % MOD;
}
return ret;
}
LL calS(LL n){
if(n<MAXN) return S[n];
if(MS.count(n)) return MS[n];
LL ret = 1;
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
ret = (ret - (r-l+1) * calS(n/l) % MOD + MOD) % MOD;
}
return MS[n] = ret;
}
void solve(){
LL ret = 0;
LL ll = (L-1)/K, rr = H/K;
for(LL l = 1, r; l <= rr; l = r + 1){
if(ll/l==0) r = rr / (rr / l);
else r = min(rr / (rr / l),ll / (ll / l));
ret = (ret + (calS(r) - calS(l-1) + MOD) * ksm(rr/l-ll/l,N) % MOD) % MOD;
}
cout << ret << endl;
}
int main(){
scanf("%d %d %d %d",&N,&K,&L,&H);
sieve();
solve();
return 0;
}
- LuoguP2522 [HAOI2011]Problem b🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e6+7;
int mu[MAXN],S[MAXN];
vector<int> prime;
bool pm[MAXN];
void sieve(){
mu[1] = 1;
fill(begin(pm),end(pm),true);
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++) S[i] = S[i-1] + mu[i];
}
int rua(int n, int m, int k){
if(n>m) swap(n,m);
n /= k, m /= k;
int ret = 0;
for(int l = 1, r; l <= n; l = r + 1){
r = min(n / (n / l),m / (m / l));
ret = ret + (S[r] - S[l-1]) * (n / l) * (m / l);
}
return ret;
}
void solve(){
int a, b, c, d, k;
cin >> a >> b >> c >> d >> k;
cout << rua(b,d,k) - rua(b,c-1,k) - rua(a-1,d,k) + rua(a-1,c-1,k) << endl;
}
int main(){
sieve();
____();
int T;
for(cin >> T; T; T--) solve();
return 0;
}
- LuoguP3327 [SDOI2015]约数个数和🔗
题解:
证明:
考虑把\(i\cdot j\)的所有因子一一映射,考虑其中一个因子中存在\(p^x\),而\(i\)中存在\(p^a\),\(j\)中存在\(p^b\)
\(\begin{cases}x\le a时只取i中的p^x \\ x>a时取i中的p^a再取j中的p^{x-a} \end{cases}\)
比如\(a=2,b=3\)
\(\begin{cases}(p^0,p^0) & x=0 \\ (p^1,p^0)&x=1\\ (p^2,p^0) & x=2 \\ (p^0,p^1) & x=3\\ (p^0,p^2) & x=4 \\ (p^0,p^3) & x=5 \end{cases}\)
对于所有质因子都这样处理
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 5e4+7;
typedef long long int LL;
int mu[MAXN],S[MAXN];
LL pre[MAXN];
vector<int> prime;
bool pm[MAXN];
void preprocess(){
mu[1] = 1;
fill(begin(pm),end(pm),true);
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++) S[i] = S[i-1] + mu[i];
for(int i = 1; i < MAXN; i++){
for(int l = 1, r; l <= i; l = r + 1){
r = i / (i / l);
pre[i] += (i / l) * (r - l + 1);
}
}
}
void solve(){
static LL n, m;
scanf("%d %d",&n,&m);
if(n>m) swap(n,m);
LL ret = 0;
for(int l = 1, r; l <= n; l = r + 1){
r = min(n / (n / l), m / (m / l));
ret += (S[r] - S[l-1]) * (pre[n/l]*pre[m/l]);
}
printf("%lld\n",ret);
}
int main(){
preprocess();
int T; for(scanf("%d",&T); T; T--) solve();
return 0;
}
- LuoguP3911 最小公倍数之和🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 5e4+7;
typedef long long int LL;
int n,c[MAXN],mu[MAXN];
LL S[MAXN],P[MAXN];
vector<int> prime;
bool pm[MAXN];
void preprocess(){
fill(begin(pm),end(pm),true);
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; i * j <= n; j++)
S[i*j] += i * mu[i];
for(int T = 1; T <= n; T++)
for(int i = 1; i <= n / T; i++)
P[T] += i * c[i * T];
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++){
int x; scanf("%d",&x);
c[x] += 1;
}
n = 50000;
preprocess();
LL ret = 0;
for(int i = 1; i <= n; i++) ret += i * S[i] * P[i] * P[i];
cout << ret << endl;
return 0;
}
- LuoguP1829 [国家集训队]Crash的数字表格 / JZPTAB🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e7+7;
typedef long long int LL;
const LL MOD = 20101009;
const LL inv2 = 10050505;
vector<int> prime;
bool pm[MAXN];
int mu[MAXN];
LL S[MAXN],pre[MAXN];
void preprocess(){
fill(begin(pm),end(pm),true);
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) mu[i] = -1, prime.push_back(i);
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(LL i = 1; i < MAXN; i++){
S[i] = (S[i-1] + i * i * mu[i]) % MOD;
pre[i] = (pre[i-1] + i) % MOD;
}
}
LL sum(LL x){ return x * (x + 1) % MOD * inv2 % MOD; }
void solve(){
int n, m;
scanf("%d %d",&n,&m);
if(n>m) swap(n,m);
LL ret = 0;
for(int l = 1, r; l <= n; l = r + 1){
r = min(n / (n / l), m / (m / l));
int N = n / l, M = m / l;
LL tp = 0;
for(int L = 1, R; L <= N; L = R + 1){
R = min(N / (N / L), M / (M / L));
tp = (tp + (S[R] - S[L-1] + MOD) * sum(N / L) % MOD * sum(M / L) % MOD) % MOD;
}
ret = (ret + (pre[r] - pre[l-1] + MOD) * tp) % MOD;
}
cout << ret << endl;
}
int main(){
preprocess();
solve();
return 0;
}
- CF435F Cowslip Collections🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const int MAXN = 1e6+7;
const LL MOD = 1e9+7;
int n,k,q,cnt[MAXN],mu[MAXN];
LL S[MAXN],f[MAXN],rf[MAXN];
bool pm[MAXN];
vector<int> prime;
LL ksm(LL a, LL b){
LL ret = 1;
while(b){
if(b&1) ret = ret * a % MOD;
b >>= 1;
a = a * a % MOD;
}
return ret;
}
void sieve(){
mu[1] = 1;
fill(begin(pm),end(pm),true);
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++)
for(int j = i; j < MAXN; j += i)
S[j] += i * mu[j/i];
}
vector<int> getFact(int x){
vector<int> vec;
for(int i = 1; i * i <= x; i++){
if(x%i!=0) continue;
vec.push_back(i);
if(i!=x/i) vec.push_back(x/i);
}
return vec;
}
LL C(int n, int m){ return m > n ? 0 : f[n] * rf[m] % MOD * rf[n-m] % MOD; }
int main(){
sieve();
scanf("%d %d %d",&n,&k,&q);
f[0] = 1;
for(int i = 1; i < MAXN; i++) f[i] = f[i-1] * i % MOD;
rf[MAXN-1] = ksm(f[MAXN-1],MOD-2);
for(int i = MAXN - 2; i >= 0; i--) rf[i] = rf[i+1] * (i+1) % MOD;
LL ret = 0;
for(int i = 1; i <= n + q; i++){
int x; scanf("%d",&x);
auto fact = getFact(x);
for(int m : fact){
cnt[m]++;
ret = (ret + (C(cnt[m],k) - C(cnt[m]-1,k) + MOD) * S[m]) % MOD;
}
if(i>n) printf("%I64d\n",ret);
}
return 0;
}
- CF1043F Make It One🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const int MAXN = 3e5+7;
const LL MOD = 998244353;
LL f[MAXN],rf[MAXN];
int n,cnt[MAXN],mu[MAXN];
vector<int> prime;
bool pm[MAXN];
LL ksm(LL a, LL b){
LL ret = 1;
while(b){
if(b&1) ret = ret * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ret;
}
void sieve(){
mu[1] = 1;
fill(begin(pm),end(pm),true);
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
}
LL C(LL n, LL m){ return m>n?0:f[n]*rf[m]%MOD*rf[n-m]%MOD; }
bool check(int m){
LL tot = 0;
for(int i = 1; i < MAXN; i++) tot = (tot + mu[i] * C(cnt[i],m)) % MOD;
return tot!=0;
}
int main(){
sieve();
f[0] = 1;
for(int i = 1; i < MAXN; i++) f[i] = f[i-1] * i % MOD;
rf[MAXN-1] = ksm(f[MAXN-1],MOD-2);
for(int i = MAXN - 2; i >= 0; i--) rf[i] = rf[i+1] * (i+1) % MOD;
scanf("%d",&n);
int g = 0;
for(int i = 1; i <= n; i++){
int x; scanf("%d",&x);
g = __gcd(x,g);
for(int j = 1; j * j <= x; j++){
if(x%j!=0) continue;
cnt[j]++;
if(j!=x/j) cnt[x/j]++;
}
}
if(g!=1){
cout << -1 << endl;
return 0;
}
int l = 1, r = n;
while(l<=r){
int mid = (l+r) >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
- CF235E. Number Challenge🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const int MAXN = 2222;
const LL MOD = 1<<30;
int a,b,c,mu[MAXN],g[MAXN][MAXN];
bool pm[MAXN];
vector<int> prime;
void sieve(){
fill(begin(pm),end(pm),true);
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
}
int gcd(int a, int b){
if(g[a][b]) return g[a][b];
return g[a][b] = g[b][a] = __gcd(a,b);
}
LL f(int n, int m){
LL ret = 0;
for(int i = 1; i <= n; i++) if(gcd(i,m)==1) ret += n / i;
return ret;
}
void solve(){
scanf("%d %d %d",&a,&b,&c);
if(a>b) swap(a,b);
LL ret = 0;
for(int m = 1; m <= c; m++){
for(int d = 1; d <= a; d++){
if(gcd(d,m)!=1) continue;
ret = (ret + c / m * (mu[d] * f(a/d,m) % MOD * f(b/d,m) % MOD) % MOD) % MOD;
}
}
cout << (ret + MOD) % MOD << endl;
}
int main(){
sieve();
solve();
return 0;
}
- CF1139D. Steps to One🔗
题解:
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const LL MOD = 1e9+7;
const int MAXN = 1e5+7;
LL ksm(LL a, LL b){
LL ret = 1;
while(b){
if(b&1) ret = ret * a % MOD;
b >>= 1;
a = a * a % MOD;
}
return ret;
}
vector<int> prime,fact[MAXN];
bool pm[MAXN];
int mu[MAXN];
LL f[MAXN];
void sieve(){
fill(begin(pm),end(pm),true);
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++)
for(int j = i; j < MAXN; j += i)
fact[j].push_back(i);
}
void solve(){
int n;
scanf("%d",&n);
f[1] = 0;
for(int i = 2; i <= n; i++){
f[i] = n;
for(int d : fact[i]){
if(d==i) continue;
for(int p : fact[i / d]) f[i] = (f[i] + f[d] * mu[p] * (n/p/d)) % MOD;
}
f[i] = f[i] * ksm(n-n/i,MOD-2) % MOD;
}
LL ans = 0, invn = ksm(n,MOD-2);
for(int i = 1; i <= n; i++) ans = (ans + f[i]) % MOD;
ans = ans * invn % MOD;
ans = (ans + 1 + MOD) % MOD;
cout << ans << endl;
}
int main(){
sieve();
solve();
return 0;
}
- CF439E. Devu and Birthday Celebration🔗
题解:
$$f[x]表示当前gcd为x的情况下期望还要加多少个数能使得gcd变成1$$view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const int MAXN = 1e5+7;
const LL MOD = 1e9+7;
int n,m,mu[MAXN];
LL f[MAXN],rf[MAXN],g[MAXN];
vector<int> prime;
bool pm[MAXN];
LL ksm(LL a, LL b){
LL ret = 1;
while(b){
if(b&1) ret = ret * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ret;
}
void sieve(){
fill(begin(pm),end(pm),true);
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(pm[i]) prime.push_back(i), mu[i] = -1;
for(int j = 0; i * prime[j] < MAXN; j++){
pm[i*prime[j]] = false;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
f[0] = 1;
for(int i = 1; i < MAXN; i++) f[i] = f[i-1] * i % MOD;
rf[MAXN-1] = ksm(f[MAXN-1],MOD-2);
for(int i = MAXN - 2; i >= 0; i--) rf[i] = rf[i+1] * (i+1) % MOD;
}
LL C(int n, int m){ return m>n?0:f[n]*rf[m]%MOD*rf[n-m]%MOD; }
void solve(){
scanf("%d %d",&n,&m);
vector<int> fact;
for(int i = 1; i * i <= n; i++){
if(n%i!=0) continue;
if(n/i>=m) fact.push_back(i);
if(i==n/i) continue;
if(i>=m) fact.push_back(n/i);
}
LL ret = 0;
for(int x : fact) ret = (ret + mu[x] * C(n/x-1,m-1)) % MOD;
printf("%I64d\n",(ret+MOD) % MOD);
}
int main(){
sieve();
int T;
for(scanf("%d",&T); T; T--) solve();
return 0;
}