1. Problem - 27E - Codeforces
给定 n ( 1 ≤ n ≤ 1000 ) n(1 \le n \le 1000) n(1≤n≤1000),找到因子个数恰好为 n n n 个的最小正整数. 保证答案不大于 1 e 18 1e18 1e18.
和 反素数 的思路是一样的,深搜
这个是枚举当前数字可以填的最高幂指数,后面的数的最高幂指数都不会比当前高。因为如果比之前的质数幂指数高,交换二者的次数,乘积会变小,因子个数却不变. 用上这个性质,速度可以提升非常非常多!
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
ull prime[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
int n;
//一定要开大点,不然会错.
ull prod = ~0ull;
void dfs(int id, int up, ull res, int cnt)
{
if(cnt > n || id >= 16) return; //剪枝
if(cnt == n && res < prod)
{
prod = res;
return; //剪枝
}
for(int i = 1; i <= up; i++)
{
//保证幂次成不升序列,剪枝
if(res * prime[id] > prod) break;
dfs(id + 1, i, res = res * prime[id], cnt * (i + 1));
}
}
int main()
{
scanf("%d", &n);
dfs(0, 64, 1, 1);
printf("%llu\n", prod);
return 0;
}
2. Problem b
求值(多组数据)
∑
i
=
x
n
∑
j
=
y
m
[
gcd
(
i
,
j
)
=
k
]
(
1
⩽
T
,
x
,
y
,
n
,
m
,
k
⩽
5
×
1
0
4
)
\sum_{i=x}^{n}\sum_{j=y}^{m}[\gcd(i,j)=k]\qquad (1\leqslant T,x,y,n,m,k\leqslant 5\times 10^4)
i=x∑nj=y∑m[gcd(i,j)=k](1⩽T,x,y,n,m,k⩽5×104)
根据容斥原理,原式可以分成 4 4 4 块来处理,每一块的式子都为
∑ i = 1 n ∑ j = 1 m [ gcd ( i , j ) = k ] \sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=k] i=1∑nj=1∑m[gcd(i,j)=k]
考虑化简该式子
∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ [ gcd ( i , j ) = 1 ] \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[\gcd(i,j)=1] i=1∑⌊kn⌋j=1∑⌊km⌋[gcd(i,j)=1]
因为 gcd ( i , j ) = 1 \gcd(i,j)=1 gcd(i,j)=1 时对答案才用贡献,于是我们可以将其替换为 ε ( gcd ( i , j ) ) \varepsilon(\gcd(i,j)) ε(gcd(i,j))( ε ( n ) \varepsilon(n) ε(n) 当且仅当 n = 1 n=1 n=1 时值为 1 1 1 否则为 0 0 0),故原式化为
∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ε ( gcd ( i , j ) ) \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\varepsilon(\gcd(i,j)) i=1∑⌊kn⌋j=1∑⌊km⌋ε(gcd(i,j))
将 ε \varepsilon ε 函数展开得到
∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ∑ d ∣ gcd ( i , j ) μ ( d ) \displaystyle\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_{d\mid \gcd(i,j)}\mu(d) i=1∑⌊kn⌋j=1∑⌊km⌋d∣gcd(i,j)∑μ(d)
变换求和顺序,先枚举 d ∣ gcd ( i , j ) d\mid \gcd(i,j) d∣gcd(i,j) 可得
∑ d = 1 μ ( d ) ∑ i = 1 ⌊ n k ⌋ [ d ∣ i ] ∑ j = 1 ⌊ m k ⌋ [ d ∣ j ] \displaystyle\sum_{d=1}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d\mid i]\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d\mid j] d=1∑μ(d)i=1∑⌊kn⌋[d∣i]j=1∑⌊km⌋[d∣j]
易知 1 ∼ ⌊ n k ⌋ 1\sim\lfloor\dfrac{n}{k}\rfloor 1∼⌊kn⌋ 中 d d d 的倍数有 ⌊ n k d ⌋ \lfloor\dfrac{n}{kd}\rfloor ⌊kdn⌋ 个,故原式化为
∑ d = 1 min ( ⌊ n k ⌋ , ⌊ m k ⌋ ) μ ( d ) ⌊ n k d ⌋ ⌊ m k d ⌋ \displaystyle\sum_{d=1}^{\min(\lfloor \frac{n}{k}\rfloor,\lfloor \frac{m}{k}\rfloor)}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor d=1∑min(⌊kn⌋,⌊km⌋)μ(d)⌊kdn⌋⌊kdm⌋
很显然,式子可以数论分块求解。
#include<bits/stdc++.h>
using namespace std;
const int N = 50010;
int prime[N], mu[N], cnt, sum[N];
bool st[N];
void sieve(int n)
{
mu[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!st[i]) prime[cnt++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= n / i; j++)
{
st[i * prime[j]] = true;
mu[i * prime[j]] = -mu[i];
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
}
}
for(int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + mu[i];
}
}
int get(int n, int i)
{
return n / (n / i);
}
int solve(int n, int m)
{
int res = 0;
for(int l = 1, r; l <= min(n, m); l = r + 1)
{
r = min(get(n, l), get(m, l));
res += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
}
return res;
}
int main()
{
sieve(N - 1);
int T;
scanf("%d", &T);
while(T--)
{
int a, b, c, d, k;
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
printf("%d\n", solve(b / k, d / k) - solve((a - 1) / k, d / k)
- solve(b / k, (c - 1) / k) + solve((a - 1) / k, (c - 1) / k));
}
return 0;
}
3. LCM Sum
求值(多组数据)
∑ i = 1 n lcm ( i , n ) s.t. 1 ⩽ T ⩽ 3 × 1 0 5 , 1 ⩽ n ⩽ 1 0 6 \sum_{i=1}^n \operatorname{lcm}(i,n)\quad \text{s.t.}\ 1\leqslant T\leqslant 3\times 10^5,1\leqslant n\leqslant 10^6 i=1∑nlcm(i,n)s.t. 1⩽T⩽3×105,1⩽n⩽106
易得原式即
∑ i = 1 n i ⋅ n gcd ( i , n ) \sum_{i=1}^n \frac{i\cdot n}{\gcd(i,n)} i=1∑ngcd(i,n)i⋅n
将原式复制一份并且颠倒顺序,然后将 n 一项单独提出,可得
1 2 ⋅ ( ∑ i = 1 n − 1 i ⋅ n gcd ( i , n ) + ∑ i = n − 1 1 i ⋅ n gcd ( i , n ) ) + n \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(i,n)}\right)+n 21⋅(i=1∑n−1gcd(i,n)i⋅n+i=n−1∑1gcd(i,n)i⋅n)+n
根据 gcd ( i , n ) = gcd ( n − i , n ) \gcd(i,n)=\gcd(n-i,n) gcd(i,n)=gcd(n−i,n),可将原式化为
1 2 ⋅ ( ∑ i = 1 n − 1 i ⋅ n gcd ( i , n ) + ∑ i = n − 1 1 i ⋅ n gcd ( n − i , n ) ) + n \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(n-i,n)}\right)+n 21⋅(i=1∑n−1gcd(i,n)i⋅n+i=n−1∑1gcd(n−i,n)i⋅n)+n
两个求和式中分母相同的项可以合并。
1 2 ⋅ ∑ i = 1 n − 1 n 2 gcd ( i , n ) + n \frac{1}{2}\cdot \sum_{i=1}^{n-1}\frac{n^2}{\gcd(i,n)}+n 21⋅i=1∑n−1gcd(i,n)n2+n
即
1 2 ⋅ ∑ i = 1 n n 2 gcd ( i , n ) + n 2 \frac{1}{2}\cdot \sum_{i=1}^{n}\frac{n^2}{\gcd(i,n)}+\frac{n}{2} 21⋅i=1∑ngcd(i,n)n2+2n
可以将相同的 gcd ( i , n ) \gcd(i,n) gcd(i,n) 合并在一起计算,故只需要统计 gcd ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 的个数。当 gcd ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 时, gcd ( i d , n d ) = 1 \displaystyle\gcd(\frac{i}{d},\frac{n}{d})=1 gcd(di,dn)=1,所以 gcd ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 的个数有 φ ( n d ) \displaystyle\varphi(\frac{n}{d}) φ(dn) 个。
故答案为
1 2 ⋅ ∑ d ∣ n n 2 ⋅ φ ( n d ) d + n 2 \frac{1}{2}\cdot\sum_{d\mid n}\frac{n^2\cdot\varphi(\frac{n}{d})}{d}+\frac{n}{2} 21⋅d∣n∑dn2⋅φ(dn)+2n
变换求和顺序,设 d ′ = n d \displaystyle d'=\frac{n}{d} d′=dn,合并公因式,式子化为
1 2 n ⋅ ( ∑ d ′ ∣ n d ′ ⋅ φ ( d ′ ) + 1 ) \frac{1}{2}n\cdot\left(\sum_{d'\mid n}d'\cdot\varphi(d')+1\right) 21n⋅ d′∣n∑d′⋅φ(d′)+1
#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
typedef long long ll;
int prime[N], phi[N], cnt;
ll g[N];
bool st[N];
void sieve(int n)
{
phi[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!st[i])
{
prime[cnt++] = i;
phi[i] = i - 1;
}
for(int j = 0; prime[j] <= n / i; j++)
{
st[i * prime[j]] = true;
if(i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for(int i = 1; i <= n; i++)
{
for(int j = i; j <= n; j += i)
{
g[j] += i * phi[i];
}
}
for(int i = 1; i <= n; i++)
{
g[i] = (g[i] + 1) * i / 2;
}
}
int main()
{
sieve(N - 1);
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
printf("%lld\n", g[n]);
}
return 0;
}
实际上可以通过巧妙的筛法线性筛出
设 g ( n ) = ∑ d ∣ n d ⋅ φ ( d ) \displaystyle \operatorname{g}(n)=\sum_{d\mid n} d\cdot\varphi(d) g(n)=d∣n∑d⋅φ(d),已知 g \operatorname{g} g 为积性函数,于是可以 Θ ( n ) \Theta(n) Θ(n) 筛出。每次询问 Θ ( 1 ) \Theta(1) Θ(1) 计算即可。
下面给出这个函数筛法的推导过程:
首先考虑 g ( p j k ) \operatorname g(p_j^k) g(pjk) 的值,显然它的约数只有 p j 0 , p j 1 , ⋯ , p j k p_j^0,p_j^1,\cdots,p_j^k pj0,pj1,⋯,pjk,因此
g ( p j k ) = ∑ w = 0 k p j w ⋅ φ ( p j w ) \operatorname g(p_j^k)=\sum_{w=0}^{k}p_j^w\cdot\varphi(p_j^w) g(pjk)=w=0∑kpjw⋅φ(pjw)
又有 φ ( p j w ) = p j w − 1 ⋅ ( p j − 1 ) \varphi(p_j^w)=p_j^{w-1}\cdot(p_j-1) φ(pjw)=pjw−1⋅(pj−1),则原式可化为
∑ w = 0 k p j 2 w − 1 ⋅ ( p j − 1 ) \sum_{w=0}^{k}p_j^{2w-1}\cdot(p_j-1) w=0∑kpj2w−1⋅(pj−1)
于是有
g ( p j k + 1 ) = g ( p j k ) + p j 2 k + 1 ⋅ ( p j − 1 ) \operatorname g(p_j^{k+1})=\operatorname g(p_j^k)+p_j^{2k+1}\cdot(p_j-1) g(pjk+1)=g(pjk)+pj2k+1⋅(pj−1)
那么,对于线性筛中的 g ( i ⋅ p j ) ( p j ∣ i ) \operatorname g(i\cdot p_j)(p_j|i) g(i⋅pj)(pj∣i),令 i = a ⋅ p j w ( gcd ( a , p j ) = 1 ) i=a\cdot p_j^w(\operatorname{gcd}(a,p_j)=1) i=a⋅pjw(gcd(a,pj)=1),可得
g ( i ⋅ p j ) = g ( a ) ⋅ g ( p j w + 1 ) \operatorname g(i\cdot p_j)=\operatorname g(a)\cdot\operatorname g(p_j^{w+1}) g(i⋅pj)=g(a)⋅g(pjw+1)
g ( i ) = g ( a ) ⋅ g ( p j w ) \operatorname g(i)=\operatorname g(a)\cdot\operatorname g(p_j^w) g(i)=g(a)⋅g(pjw)
即
g ( i ⋅ p j ) − g ( i ) = g ( a ) ⋅ p j 2 w + 1 ⋅ ( p j − 1 ) \operatorname g(i\cdot p_j)-\operatorname g(i)=\operatorname g(a)\cdot p_j^{2w+1}\cdot(p_j-1) g(i⋅pj)−g(i)=g(a)⋅pj2w+1⋅(pj−1)
同理有
g ( i ) − g ( i p j ) = g ( a ) ⋅ p j 2 w − 1 ⋅ ( p j − 1 ) \operatorname g(i)-\operatorname g(\frac{i}{p_j})=\operatorname g(a)\cdot p_j^{2w-1}\cdot(p_j-1) g(i)−g(pji)=g(a)⋅pj2w−1⋅(pj−1)
因此
g ( i ⋅ p j ) = g ( i ) + ( g ( i ) − g ( i p j ) ) ⋅ p j 2 \operatorname g(i\cdot p_j)=\operatorname g(i)+\left (\operatorname g(i)-\operatorname g(\frac{i}{p_j})\right )\cdot p_j^2 g(i⋅pj)=g(i)+(g(i)−g(pji))⋅pj2
4. Crash的数字表格
求值(对 20101009 20101009 20101009 取模)
∑ i = 1 n ∑ j = 1 m lcm ( i , j ) ( n , m ⩽ 1 0 7 ) \sum_{i=1}^n\sum_{j=1}^m\operatorname{lcm}(i,j)\qquad (n,m\leqslant 10^7) i=1∑nj=1∑mlcm(i,j)(n,m⩽107)
易知原式等价于
∑ i = 1 n ∑ j = 1 m i ⋅ j gcd ( i , j ) \sum_{i=1}^n\sum_{j=1}^m\frac{i\cdot j}{\gcd(i,j)} i=1∑nj=1∑mgcd(i,j)i⋅j
枚举最大公因数 d d d,显然两个数除以 d d d 得到的数互质
∑ i = 1 n ∑ j = 1 m ∑ d ∣ i , d ∣ j , gcd ( i d , j d ) = 1 i ⋅ j d \sum_{i=1}^n\sum_{j=1}^m\sum_{d\mid i,d\mid j,\gcd(\frac{i}{d},\frac{j}{d})=1}\frac{i\cdot j}{d} i=1∑nj=1∑md∣i,d∣j,gcd(di,dj)=1∑di⋅j
非常经典的 gcd \gcd gcd 式子的化法
∑ d = 1 n d ⋅ ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ gcd ( i , j ) = 1 ] i ⋅ j \sum_{d=1}^n d\cdot\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]\ i\cdot j d=1∑nd⋅i=1∑⌊dn⌋j=1∑⌊dm⌋[gcd(i,j)=1] i⋅j
后半段式子中,出现了互质数对之积的和,为了让式子更简洁就把它拿出来单独计算。于是我们记
sum ( n , m ) = ∑ i = 1 n ∑ j = 1 m [ gcd ( i , j ) = 1 ] i ⋅ j \operatorname{sum}(n,m)=\sum_{i=1}^n\sum_{j=1}^m [\gcd(i,j)=1]\ i\cdot j sum(n,m)=i=1∑nj=1∑m[gcd(i,j)=1] i⋅j
接下来对 sum ( n , m ) \operatorname{sum}(n,m) sum(n,m) 进行化简。首先枚举约数,并将 [ gcd ( i , j ) = 1 ] [\gcd(i,j)=1] [gcd(i,j)=1] 表示为 ε ( gcd ( i , j ) ) \varepsilon(\gcd(i,j)) ε(gcd(i,j))
∑ d = 1 n ∑ d ∣ i n ∑ d ∣ j m μ ( d ) ⋅ i ⋅ j \sum_{d=1}^n\sum_{d\mid i}^n\sum_{d\mid j}^m\mu(d)\cdot i\cdot j d=1∑nd∣i∑nd∣j∑mμ(d)⋅i⋅j
设 i = i ′ ⋅ d i=i'\cdot d i=i′⋅d, j = j ′ ⋅ d j=j'\cdot d j=j′⋅d,显然式子可以变为
∑ d = 1 n μ ( d ) ⋅ d 2 ⋅ ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ⋅ j \sum_{d=1}^n\mu(d)\cdot d^2\cdot\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}i\cdot j d=1∑nμ(d)⋅d2⋅i=1∑⌊dn⌋j=1∑⌊dm⌋i⋅j
观察上式,前半段可以预处理前缀和;后半段又是一个范围内数对之和,记
g ( n , m ) = ∑ i = 1 n ∑ j = 1 m i ⋅ j = n ⋅ ( n + 1 ) 2 × m ⋅ ( m + 1 ) 2 g(n,m)=\sum_{i=1}^n\sum_{j=1}^m i\cdot j=\frac{n\cdot(n+1)}{2}\times\frac{m\cdot(m+1)}{2} g(n,m)=i=1∑nj=1∑mi⋅j=2n⋅(n+1)×2m⋅(m+1)
可以 Θ ( 1 ) \Theta(1) Θ(1) 求解
至此
sum ( n , m ) = ∑ d = 1 n μ ( d ) ⋅ d 2 ⋅ g ( ⌊ n d ⌋ , ⌊ m d ⌋ ) \operatorname{sum}(n,m)=\sum_{d=1}^n\mu(d)\cdot d^2\cdot g(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor) sum(n,m)=d=1∑nμ(d)⋅d2⋅g(⌊dn⌋,⌊dm⌋)
我们可以 ⌊ n ⌊ n d ⌋ ⌋ \lfloor\frac{n}{\lfloor\frac{n}{d}\rfloor}\rfloor ⌊⌊dn⌋n⌋ 数论分块求解 sum ( n , m ) \operatorname{sum}(n,m) sum(n,m) 函数。
在求出 sum ( n , m ) \operatorname{sum}(n,m) sum(n,m) 后,回到定义 sum \operatorname{sum} sum 的地方,可得原式为
∑ d = 1 n d ⋅ sum ( ⌊ n d ⌋ , ⌊ m d ⌋ ) \sum_{d=1}^n d\cdot\operatorname{sum}(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor) d=1∑nd⋅sum(⌊dn⌋,⌊dm⌋)
可见这又是一个可以数论分块求解的式子!
#include<bits/stdc++.h>
using namespace std;
const int N = 10000010;
typedef long long ll;
const ll mod = 20101009;
int prime[N], cnt;
ll mu[N];
bool st[N];
void sieve(int n)
{
mu[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!st[i]) prime[cnt++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= n / i; j++)
{
st[i * prime[j]] = true;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1; i <= n; i++) mu[i] = (1ll * i * i % mod * mu[i] % mod + mu[i - 1] + mod) % mod;
}
ll g(ll n, ll m)
{
return (n * (n + 1) / 2 % mod) * (m * (m + 1) / 2 % mod) % mod;
}
ll get(ll n, ll l)
{
return n / (n / l);
}
ll sum(ll n, ll m)
{
ll res = 0;
for(ll l = 1, r; l <= min(n, m); l = r + 1)
{
r = min(min(n, m), min(get(n, l), get(m, l)));
res += (mu[r] - mu[l - 1] + mod) % mod * g(n / l, m / l) % mod;
res %= mod;
}
return res;
}
ll solve(ll n, ll m)
{
ll res = 0;
for(ll l = 1, r; l <= min(n, m); l = r + 1)
{
r = min(min(n, m), min(get(n, l), get(m, l)));
res += (l + r) * (r - l + 1) / 2 % mod * sum(n / l, m / l) % mod;
res %= mod;
}
return res;
}
int main()
{
sieve(N - 1);
ll n, m;
scanf("%lld%lld", &n, &m);
printf("%lld\n", solve(n, m));
return 0;
}
5. 约数个数和
多组数据,求
∑
i
=
1
n
∑
j
=
1
m
d
(
i
⋅
j
)
d
(
n
)
=
∑
i
∣
n
1
n
,
m
,
T
≤
5
×
1
0
4
\sum_{i=1}^n\sum_{j=1}^md(i\cdot j)\\ d(n)=\sum_{i \mid n}1\\ n,m,T\leq5\times10^4
i=1∑nj=1∑md(i⋅j)d(n)=i∣n∑1n,m,T≤5×104
其中
d
(
n
)
d(n)
d(n) 表示
n
n
n 的约数个数
要推这道题首先要了解 d d d 函数的一个特殊性质
d ( i ⋅ j ) = ∑ x ∣ i ∑ y ∣ j [ gcd ( x , y ) = 1 ] d(i\cdot j)=\sum_{x \mid i}\sum_{y \mid j}[\gcd(x,y)=1] d(i⋅j)=x∣i∑y∣j∑[gcd(x,y)=1]
再化一下这个式子
d ( i ⋅ j ) = ∑ x ∣ i ∑ y ∣ j [ gcd ( x , y ) = 1 ] = ∑ x ∣ i ∑ y ∣ j ∑ p ∣ gcd ( x , y ) μ ( p ) = ∑ p = 1 m i n ( i , j ) ∑ x ∣ i ∑ y ∣ j [ p ∣ gcd ( x , y ) ] ⋅ μ ( p ) = ∑ p ∣ i , p ∣ j μ ( p ) ∑ x ∣ i ∑ y ∣ j [ p ∣ gcd ( x , y ) ] = ∑ p ∣ i , p ∣ j μ ( p ) ∑ x ∣ i p ∑ y ∣ j p 1 = ∑ p ∣ i , p ∣ j μ ( p ) ∗ ( ∑ x ∣ i p 1 ) ∗ ( ∑ y ∣ j p 1 ) = ∑ p ∣ i , p ∣ j μ ( p ) d ( i p ) d ( j p ) \begin{aligned} d(i\cdot j)=&\sum_{x \mid i}\sum_{y \mid j}[\gcd(x,y)=1]\\ =&\sum_{x \mid i}\sum_{y \mid j}\sum_{p \mid \gcd(x,y)}\mu(p)\\ =&\sum_{p=1}^{min(i,j)}\sum_{x \mid i}\sum_{y \mid j}[p \mid \gcd(x,y)]\cdot\mu(p)\\ =&\sum_{p \mid i,p \mid j}\mu(p)\sum_{x \mid i}\sum_{y \mid j}[p \mid \gcd(x,y)]\\ =&\sum_{p \mid i,p \mid j}\mu(p)\sum_{x \mid \frac{i}{p}}\sum_{y \mid \frac{j}{p}}1\\ =&\sum_{p \mid i,p \mid j}\mu(p)*(\sum_{x \mid \frac{i}{p}}1) * (\sum_{y \mid \frac{j}{p}}1)\\ =&\sum_{p \mid i,p \mid j}\mu(p)d\left(\frac{i}{p}\right)d\left(\frac{j}{p}\right)\\ \end{aligned} d(i⋅j)=======x∣i∑y∣j∑[gcd(x,y)=1]x∣i∑y∣j∑p∣gcd(x,y)∑μ(p)p=1∑min(i,j)x∣i∑y∣j∑[p∣gcd(x,y)]⋅μ(p)p∣i,p∣j∑μ(p)x∣i∑y∣j∑[p∣gcd(x,y)]p∣i,p∣j∑μ(p)x∣pi∑y∣pj∑1p∣i,p∣j∑μ(p)∗(x∣pi∑1)∗(y∣pj∑1)p∣i,p∣j∑μ(p)d(pi)d(pj)
将上述式子代回原式
∑ i = 1 n ∑ j = 1 m d ( i ⋅ j ) = ∑ i = 1 n ∑ j = 1 m ∑ p ∣ i , p ∣ j μ ( p ) d ( i p ) d ( j p ) = ∑ p = 1 m i n ( n , m ) ∑ i = 1 n ∑ j = 1 m [ p ∣ i , p ∣ j ] ⋅ μ ( p ) d ( i p ) d ( j p ) = ∑ p = 1 m i n ( n , m ) ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ m p ⌋ μ ( p ) d ( i ) d ( j ) = ∑ p = 1 m i n ( n , m ) μ ( p ) ∑ i = 1 ⌊ n p ⌋ d ( i ) ∑ j = 1 ⌊ m p ⌋ d ( j ) = ∑ p = 1 m i n ( n , m ) μ ( p ) S ( ⌊ n p ⌋ ) S ( ⌊ m p ⌋ ) ( S ( n ) = ∑ i = 1 n d ( i ) ) \begin{aligned} &\sum_{i=1}^n\sum_{j=1}^md(i\cdot j)\\ =&\sum_{i=1}^n\sum_{j=1}^m\sum_{p \mid i,p \mid j}\mu(p)d\left(\frac{i}{p}\right)d\left(\frac{j}{p}\right)\\ =&\sum_{p=1}^{min(n,m)} \sum_{i=1}^n\sum_{j=1}^m [p \mid i,p \mid j]\cdot\mu(p)d\left(\frac{i}{p}\right)d\left(\frac{j}{p}\right)\\ =&\sum_{p=1}^{min(n,m)} \sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{m}{p}\right\rfloor} \mu(p)d(i)d(j)\\ =&\sum_{p=1}^{min(n,m)}\mu(p) \sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}d(i) \sum_{j=1}^{\left\lfloor\frac{m}{p}\right\rfloor}d(j)\\ =&\sum_{p=1}^{min(n,m)}\mu(p) S\left(\left\lfloor\frac{n}{p}\right\rfloor\right) S\left(\left\lfloor\frac{m}{p}\right\rfloor\right) \left(S(n)=\sum_{i=1}^{n}d(i)\right)\\ \end{aligned} =====i=1∑nj=1∑md(i⋅j)i=1∑nj=1∑mp∣i,p∣j∑μ(p)d(pi)d(pj)p=1∑min(n,m)i=1∑nj=1∑m[p∣i,p∣j]⋅μ(p)d(pi)d(pj)p=1∑min(n,m)i=1∑⌊pn⌋j=1∑⌊pm⌋μ(p)d(i)d(j)p=1∑min(n,m)μ(p)i=1∑⌊pn⌋d(i)j=1∑⌊pm⌋d(j)p=1∑min(n,m)μ(p)S(⌊pn⌋)S(⌊pm⌋)(S(n)=i=1∑nd(i))
那么 O ( n ) O(n) O(n) 预处理 μ , d \mu,d μ,d 的前缀和, O ( n ) O(\sqrt{n}) O(n) 分块处理询问,总复杂度 O ( n + T n ) O(n+T\sqrt{n}) O(n+Tn).
6. C. Curious
题意:计算 ∑ i = 1 n ∑ j = 1 n [ g c d ( a i , a j ) = x ] \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[gcd(a_i, a_j) = x] i=1∑nj=1∑n[gcd(ai,aj)=x]
T T T 组数据,每组数据 k k k 组询问,每次询问问一个 x x x.
1 ≤ T ≤ 10 , 1 ≤ k , n , m ≤ 1 0 5 , 1 ≤ a i ≤ m 1 \le T \le 10, 1 \le k, n, m \le 10^5, 1 \le a_i \le m 1≤T≤10,1≤k,n,m≤105,1≤ai≤m
- 莫比乌斯反演。我们设 f ( x ) = ∑ i = 1 n ∑ j = 1 n [ g c d ( a i , a j ) = x ] f(x) = \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[gcd(a_i, a_j) = x] f(x)=i=1∑nj=1∑n[gcd(ai,aj)=x],则 F ( x ) = ∑ d ∣ n f ( d ) = ∑ i = 1 n ∑ j = 1 n [ x ∣ g c d ( a i , a j ) ] F(x) = \sum\limits_{d|n}f(d) = \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[x|gcd(a_i, a_j)] F(x)=d∣n∑f(d)=i=1∑nj=1∑n[x∣gcd(ai,aj)],设 m = ∑ i = 1 n x ∣ a i m = \sum\limits_{i=1}^{n}x|a_i m=i=1∑nx∣ai,则 F ( x ) = m 2 F(x) = m^2 F(x)=m2
- 因此,令 d ′ = d x , m ′ = ∑ i = 1 n d ′ x ∣ a i d' = \frac{d}{x}, m'=\sum\limits_{i=1}^{n}d'x | a_i d′=xd,m′=i=1∑nd′x∣ai. 则 f ( x ) = ∑ x ∣ d μ ( d x ) m 2 = ∑ d ′ = 1 ∞ μ ( d ′ ) m ′ 2 f(x) = \sum\limits_{x|d}\mu(\frac{d}{x})m^2 = \sum\limits_{d'=1}^{\infty}\mu(d')m'^2 f(x)=x∣d∑μ(xd)m2=d′=1∑∞μ(d′)m′2.
- 有一个细节,就是求 m m m,那个地方有一个小 trick,就是先筛出来 1 ∼ 1 0 5 1 \sim 10^5 1∼105 范围内的数的约数。这个也很好写。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100010;
int prime[maxn], mu[maxn], cnt, a[maxn], st[maxn];
vector<int> divisors[maxn];
void sieve(int N) {
mu[1] = 1;
for (int i = 2; i <= N; i++) {
if (!st[i]) st[i] = prime[cnt++] = i, mu[i] = -1;
for (int j = 0; prime[j] <= N / i; j++) {
st[i * prime[j]] = prime[j];
if (i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i <= N; i++) {
for (int j = i; j <= N; j += i) {
divisors[j].push_back(i);
}
}
}
int main() {
sieve(maxn - 1);
int T;
scanf("%d", &T);
while (T--) {
unordered_map<int, int> times;
unordered_map<int, ll> ans;
int N, M, K;
scanf("%d%d%d", &N, &M, &K);
for (int i = 1; i <= N; i++) {
scanf("%d", &a[i]);
for (auto p : divisors[a[i]]) {
times[p]++;
}
}
while (K--) {
int x;
scanf("%d", &x);
if (ans.count(x)) {
printf("%lld\n", ans[x]);
continue;
}
for (int i = 1; i * x <= M; i++) {
ll m = times[i * x];
ans[x] += (ll)mu[i] * m * m;
}
printf("%lld\n", ans[x]);
}
}
return 0;
}
7. A. A Simple Math Problem
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q4mhmOdb-1689501390167)(数学专题训练3 数论.assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1ODEyNzEx,size_16,color_FFFFFF,t_70)]
- 莫比乌斯反演,一个很重要的作用是交换枚举次序。
- 先放一个大雪菜在莫比乌斯反演部分推到过的一个公式,防止遗忘
s ( n ) = ∑ d ∣ n μ ( d ) = { 1 , n = 1 0 , n > 1 . s(n) = \sum\limits_{d|n}\mu(d) = \begin{cases}1,n=1\\0, n>1 \end{cases}. s(n)=d∣n∑μ(d)={1,n=10,n>1.
- 推导是这样的
∑ j = 1 n ∑ i = j n F ( j ) [ g c d ( i , j ) = = 1 ] = ∑ j = 1 n F ( j ) ∑ i = j n ∑ d ∣ ( i , j ) μ ( d ) = ∑ j = 1 n ∑ i = j n ∑ d ∣ ( i , j ) F ( j ) μ ( d ) \sum\limits_{j=1}^n\sum_{i=j}^n F(j)[gcd(i, j) == 1] \\ =\sum\limits_{j=1}^nF(j)\sum\limits_{i = j}^{n}\sum\limits_{d|(i,j)}\mu(d) \\ =\sum\limits_{j=1}^{n}\sum\limits_{i=j}^n\sum\limits_{d|(i,j)}F(j)\mu(d) j=1∑ni=j∑nF(j)[gcd(i,j)==1]=j=1∑nF(j)i=j∑nd∣(i,j)∑μ(d)=j=1∑ni=j∑nd∣(i,j)∑F(j)μ(d)
- 我们尝试交换枚举次序,枚举 d d d,用于 d d d 的含义是整除 g c d ( i , j ) gcd(i,j) gcd(i,j),因此d一定整除i,且d一定整除j. 因此,我们只需要枚举d的倍数即可
原式 = ∑ d = 1 n μ ( d ) ∑ j ′ = 1 ⌊ n / d ⌋ F ( d ∗ j ′ ) ∑ i ′ = j ′ ⌊ n / d ⌋ 1 = ∑ d = 1 n μ ( d ) ∑ j ′ = 1 ⌊ n / d ⌋ F ( d ∗ j ′ ) ( ⌊ n / d ⌋ − j ′ + 1 ) . 原式 = \sum\limits_{d=1}^n\mu(d)\sum\limits_{j'=1}^{\lfloor n/d \rfloor}F(d*j') \sum\limits_{i' = j'}^{\lfloor n/d \rfloor} 1 \\ = \sum\limits_{d=1}^n\mu(d)\sum\limits_{j'=1}^{\lfloor n/d \rfloor}F(d*j') (\lfloor n/d \rfloor - j' + 1). 原式=d=1∑nμ(d)j′=1∑⌊n/d⌋F(d∗j′)i′=j′∑⌊n/d⌋1=d=1∑nμ(d)j′=1∑⌊n/d⌋F(d∗j′)(⌊n/d⌋−j′+1).
- 预处理出来莫比乌斯函数、 F F F 函数就可以了。时间复杂度是 O ( n log n ) O(n\log n) O(nlogn).
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100010;
int prime[maxn], cnt, mu[maxn], F[maxn];
bool st[maxn];
void sieve(int N)
{
mu[1] = 1;
for(int i = 2; i <= N; i++){
if(!st[i]) prime[cnt++] = i, mu[i] = -1;
for(int j = 0; prime[j] <= N / i; j++){
st[i * prime[j]] = true;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 0; i <= N; i++){
int x = i;
while(x){
F[i] += x % 10;
x /= 10;
}
}
}
int main()
{
sieve(maxn - 1);
int N;
scanf("%d", &N);
ll ans = 0;
for(int d = 1; d <= N; d++){
if(!mu[d]) continue;
ll res = 0;
for(int j = 1; j <= N / d; j++){
res += (ll)F[j * d] * (N / d - j + 1LL);
}
ans += mu[d] * res;
}
printf("%lld\n", ans);
return 0;
}
8. HDU 4549 M斐波那契数列 (费马小定理降幂&矩阵快速幂)
给一个新数列
KaTeX parse error: Expected 'EOF', got '&' at position 54: …1) * f(n - 2), &̲ n \ge 2
求
f
(
n
)
f(n)
f(n),多组数据,
0
≤
a
,
b
,
n
≤
1
0
9
0 \le a, b, n \le 10^9
0≤a,b,n≤109
不难发现, f ( n ) = b F i b ( n ) a F i b ( n − 1 ) f(n) = b^{Fib(n)}a^{Fib(n-1)} f(n)=bFib(n)aFib(n−1). 但是用费马小定理降幂的时候一定要小心 a x ≡ a x ( m o d p − 1 ) ( m o d p ) a^x \equiv a^{x \pmod {p-1}} \pmod p ax≡ax(modp−1)(modp)
#include<bits/stdc++.h>
using namespace std;
const int N = 2;
typedef long long ll;
const ll mod = 1e9 + 7;
ll mod_pow(ll x, ll n)
{
ll res = 1;
while(n)
{
if(n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
void mul(ll c[], ll a[][N], ll b[])
{
static ll tmp[N];
memset(tmp, 0, sizeof tmp);
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
tmp[i] = (tmp[i] + a[i][j] * b[j]) % (mod - 1);
}
}
memcpy(c, tmp, sizeof tmp);
}
void mul(ll c[][N], ll a[][N], ll b[][N])
{
static ll tmp[N][N];
memset(tmp, 0, sizeof tmp);
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
for(int k = 0; k < 2; k++)
{
tmp[i][j] = (tmp[i][j] + a[i][k] * b[k][j]) % (mod - 1);
}
}
}
memcpy(c, tmp, sizeof tmp);
}
int main()
{
ll a, b, n;
while(cin >> a >> b >> n)
{
if(n == 0)
{
printf("%lld\n", a);
continue;
}
n--;
ll fib[2] = {0, 1};
ll f[][2] = {{0, 1}, {1, 1}};
while(n)
{
if(n & 1) mul(fib, f, fib);
mul(f, f, f);
n >>= 1;
}
//printf("%lld\n", fib[1]);
ll res = mod_pow(b, fib[1]) * mod_pow(a, fib[0]) % mod;
printf("%lld\n", res);
}
return 0;
}
9. HDU 4196 Remoteland
题意: 在 1 ∼ n 1 \sim n 1∼n 中挑选不同的数字,使得它们的乘积是完全平方数,并且他们的乘积最大。求这个乘积模 1 e 9 + 7 1e9+7 1e9+7.
其实就是把这些数字全部乘起来,然后统计一下每个质数出现多少次,如果出现奇数次,在把乘积除以这个质数。
也是完全平方数
Problem - 1497E1 - Codeforces
- 这个题想复杂了。我们把所有的数字的质因数的幂都模2,这样子的话,我们从前往后遍离数组,并用一个map记录之前哪些数字出现过。
- 如果新加进来的改变的数字并不存在于 map 中,说明当前数字加入当前区间不会引起冲突,于是把这个数字加入当前的区间之中。
- 如果之前这个数出新过,那么就在这个数前面画一条分界线,把map清空,把这个数加到map里面,然后答案加1.
#include<bits/stdc++.h>
using namespace std;
const int N = 10000010;
int prime[N], cnt, st[N];
void sieve(int n)
{
for(int i = 2; i <= n; i++){
if(!st[i]) prime[cnt++] = st[i] = i;
for(int j = 0; prime[j] <= n / i; j++){
st[i * prime[j]] = prime[j];
if(i % prime[j] == 0) break;
}
}
}
int change(int x)
{
int res = 1;
while(x > 1){
int u = st[x];
int cnt = 0;
while(x % u == 0){
cnt++;
x /= u;
}
if(cnt & 1) res *= u;
}
return res;
}
int main()
{
sieve(N - 1);
int T;
scanf("%d", &T);
while(T--){
set<int> S;
int n, k;
scanf("%d%d", &n, &k);
int ans = 1, tmp;
for(int i = 1; i <= n; i++){
scanf("%d", &tmp);
tmp = change(tmp);
if(S.count(tmp)){
ans++;
S.clear();
}
S.insert(tmp);
}
printf("%d\n", ans);
}
return 0;
}
Problem - 1497E2 - Codeforces
- 给一个序列 n ≤ 2 e 5 n \le 2e5 n≤2e5,问最少分割成几个连续字段,使得每个连续字段中不存在两个数的积是完全平方数. 可以改变中间的某个数字至多 k ( k ≤ 20 ) k(k \le 20) k(k≤20) 次,改为任意的数字即可.
- 我们先处理出 L e f t ( i , j ) Left(i,j) Left(i,j) 表示从 i i i 开始,可以删掉 j j j 个数字,满足 [ l , i ] [l,i] [l,i] 中间是合法连续子序列的最往左的左区间端点是多少. 这个可以用双指针在 O ( n k ) O(nk) O(nk) 的时间内解决.
- 然后令 f ( i , j ) f(i,j) f(i,j) 表示前 i i i 个数字,改变 j j j 个数字的最少划分数是多少. 这个我们可以枚举 x ∈ [ 0 , j ] x \in [0,j] x∈[0,j], l = L e f t ( i , j ) l = Left(i,j) l=Left(i,j),可以分为从两块,及 [ 1 , l − 1 ] [1, l - 1] [1,l−1] 的最优划分加上 [ l , i ] [l,i] [l,i] 作为一个完整连续子段,并且前者改变 j − x j - x j−x 次,后者改变 x x x 次.
f ( i , j ) = min { f ( i , j ) , f ( l − 1 , j ) + 1 } f(i,j) = \min\{f(i,j),f(l-1,j) + 1\} f(i,j)=min{f(i,j),f(l−1,j)+1}
- 初始化的时候, f f f初始化为正无穷, f ( 0 , 0 ) f(0,0) f(0,0) 初始化为1即可.
#include<bits/stdc++.h>
using namespace std;
const int N = 200010, M = 10000010;
int prime[M], st[M], cnt;
void sieve(int n)
{
for(int i = 2; i <= n; i++){
if(!st[i]) prime[cnt++] = st[i] = i;
for(int j = 0; prime[j] <= n / i; j++){
st[i * prime[j]] = prime[j];
if(i % prime[j] == 0) break;
}
}
}
int change(int x)
{
vector<int> res;
while(x > 1){
int u = st[x];
int cnt = 0;
while(x % u == 0){
x /= u;
cnt++;
}
if(cnt & 1) res.push_back(u);
}
int ans = 1;
for(auto p : res){
ans = ans * p;
}
return ans;
}
int a[N], n, k, Left[N][30], f[N][30];
unordered_map<int, int> Map(N);
int main()
{
sieve(M - 1);
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++){
int x;
scanf("%d", &x);
a[i] = change(x);
}
for(int i = 1; i <= n; i++){
for(int j = 0; j <= k; j++){
Left[i][j] = 0;
f[i][j] = 1e9;
}
}
f[0][0] = 0;
for(int lim = 0; lim <= k; lim++){
Map.clear();
int cnt = 0;
for(int i = 1, j = 1; i <= n; i++){
Map[a[i]]++;
if(Map[a[i]] > 1) cnt++;
while(i >= j && cnt > lim){
if(Map[a[j]] > 1){
cnt--;
}
Map[a[j]]--;
j++;
}
Left[i][lim] = j;
}
}
for(int i = 1; i <= n; i++){
for(int j = 0; j <= k; j++){
for(int x = 0; x <= j; x++){
int l = Left[i][x];
f[i][j] = min(f[i][j], f[l - 1][j - x] + 1);
}
}
}
int ans = 1e9;
for(int j = 0; j <= k; j++){
ans = min(ans, f[n][j]);
}
printf("%d\n", ans);
}
return 0;
}
HDU 3221 Brute-force Algorithm (矩阵 欧拉定理降幂)
广义欧拉定理
FZU 1759 Super A^B mod C
HDU 2837 Calculation
The Boss on Mars
给出正整数 n n n,满足 1 ≤ n ≤ 1 0 8 1 ≤ n ≤ 10^8 1≤n≤108,求 ∑ i = 1 n [ ( n , i ) = 1 ] i 4 m o d ( 1 0 9 + 7 ) \sum\limits_{i=1}^{n} [(n,i)=1] i^4 \mod (10^9 + 7) i=1∑n[(n,i)=1]i4mod(109+7)。
Mod Tree
给出方程 A x ≡ B ( m o d C ) A^x \equiv B \pmod C Ax≡B(modC),求 x x x 的最小非负整数解. 1 ≤ A , B , C ≤ 1 0 9 1 \le A,B,C \le 10^9 1≤A,B,C≤109
数论之神
给出方程 X A ≡ B ( m o d C ) X^A \equiv B \pmod C XA≡B(modC),求 x x x 在 [ 0 , C ) [0,C) [0,C) 上的整数解的个数.
1 ≤ A , B , C ≤ 1 0 9 1\le A, B, C \le 10^9 1≤A,B,C≤109,且 C C C 是奇数.
Interesting Yang Hui Triangle
给出非负整数 n n n 和素数 P P P,统计 C x n C_x^n Cxn 中有多少个不是 P P P 的倍数
n ≤ 1 0 9 , P < 1000 n \le 10^9, P < 1000 n≤109,P<1000