洛谷P5495 【模板】Dirichlet 前缀和 题解
题意:
给定一个长度为 $n$ 的数列 $a_1,a_2,a_3,\dots,a_n$。
现在你要求出一个长度为 $n$ 的数列 $b_1,b_2,b_3,\dots,b_n$,满足
由于某些神秘原因,这里的 $b_k$ 要对 $2^{32}$ 取模。
输入格式:
为了避免过大的输入,本题的输入使用随机数生成器。
输入中只有一行两个整数 $n,\mathrm{seed}$。其中 $\mathrm{seed}$ 为 $32$ 位无符号整数,用来生成数据。
接下来,你要调用 $n$ 次随机数生成器,分别生成 $a_1\sim a_n$。随机生成器见原题链接。
输出格式:
为了避免过大的输出,你只需输出一个 $32$ 位无符号整数,表示所有 $b_i$ 的异或和。
数据范围:
$1\leq n\leq 2\times 10^7$,$0\leq \mathrm{seed}< 2^{32}$。
设 $i = \prod p_k^{\alpha_k},~j = \prod p_k^{\beta_k}$ ,其中 $p$ 均为素数。
那么 $a_i$ 对 $b_j$ 有贡献当且仅当 $\forall k,~\alpha_k \le \beta_k$ 。
可以发现这是一个高维前缀和,即如果我们给每个 $p$ 都开一维的话,答案可以这么算
这里没写全,后面的省略号表示容斥要减去的东西,这个应该很好理解。
不过这意思有些过于蠢了。我们已经知道 $\prod p_i^{x_i}$ 了,完全可以记一个 $f_i$ ,每次从质因子处得到贡献。
直接枚举质因子还是很蠢,我们可以用埃氏筛。
这样时间复杂度就是 $\mathcal{O}(n \log \log n)$ ,埃氏筛的复杂度证明参考 link
代码:
#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
#define uint unsigned int
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)(2e7 + 15))
uint _, res, f[N], a[N]; char chk[N];
uint rd() { _ ^= _ << 13; _ ^= _ >> 17; _ ^= _ << 5; return _; }
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int n; cin >> n >> _;
rep(i, 1, n) f[i] = a[i] = rd();
chk[1] = 1;
rep(i, 1, n)
{
if(!chk[i]) rep(j, 1, n / i) {
f[i * j] += f[j], chk[i * j] = true;
} res ^= f[i];
}
cout << res << '\n';
return 0;
}