首页 > 其他分享 >闲话 221224

闲话 221224

时间:2022-12-24 19:35:06浏览次数:56  
标签:__ 221224 int 闲话 T1 text mod bnd

闲话

今晚 ABC!
看我是不是卡死在 B 题上(

jjdw;你这太菜了 不行啊

今天的推歌是 I LOST(2022Remaster) by はるまきごはん feat. 初音ミク
好最后还是回到了饭的歌呢!
这首歌我总是无意识地哼
好听好听!

\(\text{Powerful Number}\) 筛

还差一个筛子。以前一直没法理解,现在就班门弄斧说一说吧。

记 \(*\) 为狄利克雷卷积,\(\times\) 或隐式结合为数乘,\(+\) 为数加,\(S(f, n)\) 为对数论函数 \(f\) 求和,上界为 \(n\)。

\(\text{Powerful Number}\) 筛,简称 \(\text{PN}\) 筛,应用了特殊构造的狄利克雷卷积,将点值归类至 \(\text{PN}\) 处,从而加速求解。

首先介绍一下 \(\text{Powerful Number}\),下面简称 \(\text{PN}\)。

记 \(n\) 的质因数分解为 \(\prod_{i} p_i^{c_i}\)。\(n\) 为 \(\text{PN}\) 当且仅当 \(\forall i,\ c_i > 1\)。容易发现任意 \(\text{PN}\) 可以表示为 \(a^2b^3\) 的形式:对于偶数的 \(c_i\) 直接合并入 \(a\),其余情况取出 \(p_i^3\) 合入 \(b\),再将剩余部分合入 \(a\)。

可以发现,\(n\) 以内的 \(\text{PN}\) 有 \(O(\sqrt n)\) 个。
证明:

\[\int_1^{\sqrt {n}} \sqrt[3]{\frac{n}{x^2}} \text dx = O(\sqrt n) \]

下面的操作中需要找到所有 \(n\) 以内的 \(\text{PN}\)。我们可以首先筛出 \(\sqrt n\) 以内的质数,随后 dfs 各质数的指数即可。由于不会产生无用搜索,总时间复杂度为 \(O(\sqrt n)\)。

假设我们需要求解积性函数 \(f\) 的前缀和 \(S(f, n)\)。应用 PN 筛的要求是存在一个易求前缀和的积性函数函数 \(g\),满足 \(\forall p\text{ is prime},\ f(p) = g(p)\)。

我们构造这么一个 \(g\),再构造 \(h\) 满足 \(f = g * h\)。容易发现 \(h\) 积性。观察 \(h\) 的取值。取素数 \(p\),\(f(p) = g(1)h(p) + g(p)h(1) = h(p) + g(p) = h(p) + f(p)\)。因此 \(h\) 在任意质数处的取值均为 \(0\)。归纳得到 \(h\) 只在 \(\text{PN}\) 处有值。

根据 \(f = g*h\),

\[\begin{aligned} & S(f, n) \\ = \ & \sum_{i=1}^n f(i) \\ = \ & \sum_{i=1}^n \sum_{d|i} h(d) g\left(\frac id\right) \\ = \ & \sum_{d=1}^n h(d) \sum_{i = 1}^{\lfloor n / d\rfloor} g(i) \\ = \ & \sum_{d=1}^n h(d) S(g,\left\lfloor\frac nd \right\rfloor) \\ = \ & \sum_{d \text{ is PN}}^n h(d) S(g,\left\lfloor\frac nd \right\rfloor) \end{aligned}\]

随后只需要找到 \(h\) 的所有取值即可。这点可以在枚举 \(\text{PN}\) 时完成。为此我们还需要得到每个 \(h(p^c)\)。

有两种方法。第一种是简单地找到 \(h(p^c)\) 仅关于 \(p,c\) 的计算式。而第二种是由 \(f(p^c) = \sum_{i = 0}^c g(p^i) h(p^{c - i})\) 得到 \(h(p^c) = f(p^c) - \sum_{i = 1}^{c} g(p^i) h(p^{c - i})\)。还可以分段打表

构造 \(\text{PN}\) 筛的步骤如下:

  1. 绞尽脑汁或者利用科技想出一个好求的 \(g\)。
  2. 计算 \(h(p^c)\)。
  3. dfs 过程中累计答案。

讨论时间复杂度。

第一部分复杂度是 \(O(1\text{ min})\sim O(\infty)\) 不等。

第二部分默认采用第二种方法,第一种方法易分析。
由于需要找到每个 \(p \le \sqrt n\) 的每个 \(c = O(\log n)\) 位置的点值,因此点值数量是 \(O(\sqrt n)\) 的。每个 \(h(p^c)\) 都需要重新枚举一遍 \(1\sim c\),因此总时间复杂度为 \(O(\sqrt n \log n)\)。这个上界较松。同时根据 \(h\) 的性质可以再加优化。

第三部分的复杂度依赖于计算 \(S(g, n)\) 的复杂度。如果可以 \(O(1)\) 计算,则这部分的复杂度为 \(O(\sqrt n)\)。而借助杜教筛的总复杂度有 \(O(n^{2/3})\)。

\(\text{PN}\) 筛部分的空间复杂度显然为 \(O(\sqrt n)\)。

这东西被 fjzzq 称作”杜教筛的一个拓展“。确实,从构造到生成都很像。
但是感觉这东西还是在与杜教筛剥离的情况下能得到更优秀的(理论)复杂度。

放一道 command-block 博客里的例题:

设积性函数 \(f\) 满足 \(f(p^c) = p^{c\times k_1} + p^{c\times k_2}\),求 \(S(f, n)\)。

\(1\le n\le 10^{12}, 1\le k_1, k_2\le 10\)。

考虑素数拟合,\(f(p) = p^{k_1} + p^{k_2}\),容易发现构造 \(g_1 = \text{id}_{k_1}, g_2 = \text{id}_{k_2}\) 即可得到 \(g = g_1 * g_2\)。
考虑 \(h(p^c)\),我们就需要得到得到 \(g\) 的前 \(\sqrt n\) 个点值。首先得到 \(g_1, g_2\),这可以直接线性筛出来,复杂度为 \(\widetilde O(\sqrt n)\)。随后在 \(O(\sqrt n \log n)\) 的复杂度内做狄利克雷卷积可得。
\(S(g, n)\) 可以考虑 \(k\) 的取值较小,\(\text{id}_k\) 任意位置的前缀和都可以 \(O(1)\),这样可以通过整除分块 \(O(\sqrt n)\) 算得。在取 \(\text{PN}\) 时计算,时间复杂度易证得 \(O(\sqrt n \log n)\)。

因此有总时间复杂度 \(O(\sqrt n\log n)\)。

推荐阅读:一类积性函数的特殊前缀和问题,whx1003

板子就放 \(\text{Min25}\) 板子的代码吧。贺 OIwiki 的。

需要注意的是可能乘爆 ll。Submission.

code
#include <bits/stdc++.h>
#define int long long
using namespace std; using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
template <typename T> T rand(T l, T r) { return uniform_int_distribution<T>(l, r)(rnd); }
template <typename T> void get(T & x) {
	x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-', ch = getchar();
	while ('0' <= ch and ch <= '9') x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); f && (x = -x); 
} template <typename T, typename ... Args> void get(T & a, Args & ... b) { get(a); get(b...); }
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
template <typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
template <typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define ufile(x) 
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define Aster(i, s) for (int i = head[s], v; i; i = e[i].next)
#define all(s) s.begin(), s.end()
#define eb emplace_back
#define pb pop_back
#define em emplace
const int N = 2e6 + 10, L = 2e6;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;

// int mod;
// const int mod = 10007;
// const int mod = 469762049, g = 3;
// const int mod = 998244353; // const int g = 3;
// const int mod = 1004535809, g = 3;
const int mod = 1e9 + 7;
// const int mod = 1e9 + 9;
// const int mod = 1e9 + 3579, bse = 131;
/* add / sub */ 			template <typename T1, typename T2> T1 add(T1 a, T2 b) { return (a += b) >= mod ? a - mod : a; } template <typename T1, typename ...Args> T1 add(T1 a, Args ... b) { return add(a, add(b...)); } template <typename T1, typename T2> T1 sub(T1 a, T2 b) { return (a -= b) < 0 ? a + mod : a; } template <typename T1, typename ...Args> T1 sub(T1 a, Args ... b) { return sub(a, add(b...)); } template <typename T1, typename T2> void addi(T1 & a, T2 b) { (a += b) >= mod ? (a -= mod) : true; } template <typename T1, typename ...Args> void addi(T1 & a, Args ...b) { addi(a, add(b...)); } template <typename T1, typename T2> void subi(T1 & a, T2 b) { (a -= b) < 0 ? (a += mod) : true; } template <typename T1, typename ...Args> void subi(T1 & a, Args ...b) { subi(a, add(b...)); }
/* Fastmod / mul */ 		struct FastMod { int m; ll b; void init(int _m) { m = _m; if (m == 0) m = 1; b = ((lll)1<<64) / m; } FastMod(int _m) { init(_m); } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod(mod); int mul(int a, int b) { return Mod(1ll * a * b); } template <typename T1, typename T2> int mul(T1 a, T2 b) { return Mod((long long)(1ll * a * b)); } template <typename T, typename ...Args> int mul(T a, Args ...b) { return mul(a, mul(b...)); }  template <typename T1, typename T2> void muli(T1 & a, T2 b) { a = Mod(1ll * a * b); } template <typename T1, typename ...Args> void muli(T1 & a, Args ...b) { muli(a, mul(b ...)); } // /* trivial multiple function(idk whether its useful*/ int mul(int a, int b) { return 1ll * a * b % mod; } template <typename T1, typename T2> int mul(T1 a, T2 b) { return (long long)(1ll * a * b) % mod; } template <typename T, typename ...Args> int mul(T a, Args ...b) { return mul(a, mul(b...)); }
/* qp init C */ 			template <typename T1, typename T2> T1 qp(T1 a, T2 b) { T1 ret = 1; for (; b > 0; a = mul(a, a), b >>= 1) if (b & 1) ret = mul(ret, a); return ret; } int fac[N], inv[N], ifc[N]; template<typename T1> void init_fac(T1 bnd, int mask = 0b111) { if ((mask >> 2) & 1) { static int __var_fac_bnd; if (__var_fac_bnd == 0) fac[0] = fac[1] = __var_fac_bnd = 1; rep(i, __var_fac_bnd + 1, bnd) fac[i] = mul(fac[i - 1], i); __var_fac_bnd = bnd; } if ((mask >> 1) & 1) { static int __var_inv_bnd; if (__var_inv_bnd == 0) inv[0] = inv[1] = __var_inv_bnd = 1; rep(i, __var_inv_bnd + 1, bnd) inv[i] = mul(mod - mod / i, inv[mod % i]); __var_inv_bnd = bnd; } if ((mask >> 0) & 1) { static int __var_ifac_bnd, __var_inv_bnd; if (__var_ifac_bnd == 0) ifc[0] = ifc[1] = __var_ifac_bnd = 1; if (__var_inv_bnd < bnd) init_fac(bnd, 0b010); rep(i, __var_ifac_bnd + 1, bnd) ifc[i] = mul(ifc[i - 1], inv[i]); __var_ifac_bnd = bnd;  } } template<typename T1, typename T2> int C(T1 n, T2 m) { if (n < m) return 0; return mul(fac[n], ifc[m], ifc[n - m]); } template<typename T1, typename T2> int invC(T1 n, T2 m) { if (n < m) return 0; return mul(ifc[n], fac[m], fac[n - m]); }
// /* inv 2/3/6 / phi */ 		constexpr int __var_pow(int a, int b) { int ret = 1; for (; b > 0; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod; return ret; } constexpr int __var_phi(int x) { if (x <= 2) return 1; int ret = x; for (int i = 2; 1ll * i * i <= x; ++i)  if (x % i == 0) { ret = ret / i * (i - 1); while (x % i == 0) x /= i; } if (x > 1) ret = ret / x * (x - 1); return ret; } const int __phi_mod = __var_phi(mod); const int inv2 = __var_pow(2, __phi_mod - 1), inv3 = __var_pow(3, __phi_mod - 1), inv6 = __var_pow(6, __phi_mod - 1);

ll n;
int ans, inv2, inv6, h[N][40];
bool vis[N][40];
int mp[N];

int g[N], sg[N], prime[N], cnt, phi[N];
void sieve(int n = L) {
	phi[1] = 1;
	rep(i,2,n) {
		if (!phi[i]) phi[i] = i - 1, prime[++ cnt] = i;
		rep(j,1,cnt) {
			int t = i * prime[j];
			if (t > n) break;
			if (i % prime[j] == 0) {
				phi[t] = 1ll * phi[i] * prime[j];
				break;
			} else phi[t] = 1ll * phi[i] * phi[prime[j]];
		}
	} 
	rep(i,1,n) g[i] = mul(i, phi[i]);
	rep(i,1,n) sg[i] = add(sg[i - 1], g[i]);
	rep(i,1,cnt) h[i][0] = 1, h[i][1] = 0, vis[i][0] = vis[i][1] = 1;
	inv2 = (mod + 1) / 2;
	inv6 = (mod + 1) / 6;
	memset(mp, -1, sizeof mp);
}

int S1(ll x) { x = Mod(x); return Mod(x * (x + 1) >> 1); }
int S2(ll x) { x = Mod(x); return mul(x, x + 1, 2 * x + 1, inv6); }

int getg(ll x) {
	if (x <= L) return sg[x];
	if (~mp[n / x]) return mp[n / x];
	int ret = S2(x);
	for (ll l = 2, r, t; l <= x; l = r + 1) {
		t = x / l, r = x / t;
		ret = sub(ret, mul(sub(S1(r), S1(l - 1)), getg(t)));
	} 
	return mp[n / x] = ret;
}

void dfs(ll d, int hd, int pid) {
	ans = add(ans, mul(hd, getg(n / d)));
	rep(i,pid,cnt) {
		if (i > 1 and d * prime[i] * prime[i] > n) break;
		for (ll x = d * prime[i] * prime[i], c = 2; 0 < x and x <= n; x *= prime[i], ++ c) {
			if (!vis[i][c]) {
				int f = qp(prime[i], c), g = mul(prime[i], prime[i] - 1), t = mul(prime[i], prime[i]);
				f = mul(f, sub(f, 1));
				rep(j,1,c) {
					f = sub(f, mul(g, h[i][c - j]));
					g = mul(g, t);
				} h[i][c] = f;
				vis[i][c] = 1;
			}
			if (h[i][c]) dfs(x, mul(hd, h[i][c]), i + 1);
		}
	}
}

signed main() {
	cin >> n;
	sieve();
	dfs(1, 1, 1);
	cout << ans << '\n';
}

标签:__,221224,int,闲话,T1,text,mod,bnd
From: https://www.cnblogs.com/joke3579/p/chitchat221224.html

相关文章

  • 20221224
    早上六点半出发,一路上太阳在背后一点点升起,天是奇妙的颜色。时隔将近半个月再次看到了\(\text{Fido_Puppy,Licykoc,Lanos212,_edge_}\)巨佬,认识了新来的\(\text{......
  • 【221224PH-2】现有质量均为m的甲乙两种金属,密度分别为p甲,p乙,且p甲>p乙.现按照一定
    注意先参阅【221224PH-1】.......
  • 【221224-1】已知:a的平方/(a+1)是整数 求:a=?
    将原有的假分式变成整数加真分式是开门钥匙。......
  • 【221224PH-1】两种物质的密度为P1和P2,各取一定质量混合,若混合后密度为(P1+P2)/2,且混合
    ......
  • 【20221224】每日一题
    classSolution{public:stringlargestMerge(stringword1,stringword2){stringans;inti=0,j=0;while(i<word1.size()||......
  • 闲话 22.12.21
    闲话什么时候结束字符串啊(我想看多项式了(怎么有人开始推歌了(那我也整点杂的活吧今日推歌是须臾永恒Zeno&星尘Minus建议听一下还是比较震撼的好听!已经循环不......
  • 闲话 22.12.20
    闲话发现我必须得整个linux虚拟机了(以前因为麻烦没整成功一直在摆着但是今天这没有-fsanitize就寄了这次一定!有点晚就写到这吧这cnblogs不让我发啊加载不出......
  • 闲话 22.12.19
    闲话今天闲话水点就水点吧也习惯了不是吗今天在随机歌看到情绪的一首歌《无法停止的白情》曲调好熟悉好听!作词作曲编曲:春卷饭彳亍已经在循环了今日SAM!一阶微分......
  • 闲话 22.12.18
    闲话?本来想颓一整天的不知不觉就到现在了呢不是很理解jijidawang数个月前莫比乌斯反演就爆踩我了%%%%最近闲话的阅读量忽高忽低欸不懂不懂溜了溜了\(\text{Min_25......
  • 12.17 闲话
    当时好像就排在我后面,我还听到他们聊天。为啥我碰不上妹子和我一起撑伞,自闭了。/ll但是期末复习不完了,怎么办???物理依托答辩,怎么办???化学依托答辩,怎么办???语文依托答辩,怎么办......