Dirichlet 前缀和

P5495 Dirichlet 前缀和 题意

\[\sum \limits_{i|k}a_i , k \in [1,n] \]

其中

\[1 \le n \le 2 \times 10^7 , 0 \le a_i \le 2^{32} \]

分析

我们考虑从高维点的角度来看。

建立一个以质数维度的坐标系,由于每一个数都能被拆为唯一形式的质数积,它们在坐标系中都有对应的点。

\(6\) 能被拆为 \(2^1 \times 3^1\) ,在 \(2-3\) 的坐标系中,坐标即为 \((1,1)\)

考虑高维前缀和,先上代码:

for(int i=1;i<=cnt;i++)
		for(int j=1;prime[i]*j<=n;j++)
			F[prime[i]*j]+=F[j];

乍一看可能根本看不懂,但你得一步步来分析。

首先明确一点,在坐标系中,如果有一个正整数 \(a\) ,它的每一个坐标值都不大于另一个正整数 \(b\) 的对应每一个坐标值。

那么将 \(a\)\(b\) 拆开来, \(a\) 的每一个质因子次数都不大于 \(b\) 的每一个质因子次数。

显然 \(a\)\(b\) 的约数,反过来,\(b\) 当然也是 \(a\) 的倍数。

再回过头来看一下代码:

for(int i=1;i<=cnt;i++)
		for(int j=1;prime[i]*j<=n;j++)
			F[prime[i]*j]+=F[j];

第一层循环显然是在枚举每一个质数,即每一个维度

然后由第二层循环,在当前这一维度给它从小到大做前缀和

因为是当前这一质数的维度,所以在你给这一个数乘上一个当前质数时,这个数的当前坐标值才会 \(+1\)

似这样,在每一维度都做一遍前缀和,最终 \(F'(n)\) 就等于所有坐标值都小于它的所有 \(F\) 的和,即为它的所有约数的 \(F\) 值的和

形式化的,写作

\[F'(n)= \sum \limits_{d|n} F(d) \]

显然,\(F'\) 数组即为所求,按题目要求,将其全部异或输出即可。

P2714 四元组统计 题意

\(n\) 个正整数 \(a_i\),你要统计有多少个四元组满足 \(gcd(a_i,a_j,a_k,a_l) = 1\)

其中 \(4 \le n \le 10000 ,1 \le ai \le 10000\) ,且数据组数不超过 \(100\).

分析

同上题,考虑高维后缀和,使得 \(F'(n)= \sum \limits_{n|T} F(T)\) .

再令 \(F'(n)=F(n) \times (F(n)-1) \times (F(n)-2) \times (F(n)-3) \times \frac{1}{24}\)

使得 \(F(n)\) 等于公约数有 \(n\) 的四元组的个数

再做高维差分,减去公约数为 \(n\) 的倍数的方案数,使得 \(F(n)\) 等于最大公约数为 \(n\) 的四元组的个数, \(F(1)\) 即为所求。

差分代码如下:

for(int i=1;prime[i]<=maxx;i++)
			for(int j=1;j*prime[i]<=maxx;j++)
				F[j]-=F[j*prime[i]];
posted @ 2023-08-06 15:07  ForBiggerWorld  阅读(33)  评论(0)    收藏  举报