2021牛客多校第六场G Hasse Diagram

题意:哈斯图是有限偏序集的一种表示形式,对于任意正整数n,n的因子根据它们的可除性自然地形成了一个哈斯图。记\(H_n\)为n的因子形成的哈斯图,对于任意两个因子u,v,哈斯图中边\((u,v)\)存在当且仅当存在一个质数\(p\),使得\(u=pv\)

给定一个正整数n,求\(H_1,H_2,\cdots,H_n\)中的边数和.

\(H(i)\)的边数为\(f(i)\)

那么若i为质数的幂,即\(i=p^e\)时,\(f(i)=f(p^e)=e\)

否则,假设\(i=\prod p^e\)枚举\(i\)的质因数及其次数,得

\[f(i)=(e+1)f(i/p^e)+e\times d(i/p^e) \]

其中\(d(x)\)表示\(x\)的因数个数。

这个式子的含义是,\(f(i/p^e)\)中的任意一条边\((u,v)\)的两端可以乘上\(p\)\(1\)\(e\)次幂,可以得到e条新边,再算上\(f(i/p^e)\),就是\((e+1)f(i/p^e)\)。并且\(f(i/p^e)\)的每个因子\(x\),都可以贡献\(e\)条形如\((p^kx,p^{k-1}x)\)的边。

\(f(x)\)\(d(x)\)均符合“在质数的次幂处可以快速求值“这一条件,并且\(d(x)\)是完全积性函数。但\(f(x)\)没有积性,不好搞。

\(f(p) = 1\),可以取\(f(x)=1\)求其在质数处的前缀和(质数个数)(min_25的第一部分)

再由上面那个递推式可设\(S(i, j)\)\([2,i]\)中,满足\(x\)的最小质因子比第\(j\)个质数大的\(f(x)\)的和。那么最终所求的答案即为\(S(n,0)\)

min_25的第二部分的递推式为

\[S(i,j)=g(i,|P|)-g(p_j,|P|)+\sum_{k>j}\sum_{e=1}^{p_k^e\le n}f(p_k^e)(S(\lfloor\frac{i}{p_k^e}\rfloor,k)+[e>1]) \]

这是在

\[f(i) = f(p^e)\times f(i/p^e) \]

的情况下推出的。

而本题中应基于上述的递推式改为

\[S(i,j)=g(i,|P|)-g(p_j,|P|)+\sum_{k>j}\sum_{e=1}^{p_k^e\le n}( (e+1)S(\lfloor\frac{i}{p_k^e}\rfloor,k)+e(S_d(\lfloor\frac{i}{p^e_k}\rfloor,k)+[e>1])) \\ S_d(i,j)=2*(g(i,|P|)-g(p_j,|P|))+\sum_{k>j}\sum_{e=1}^{p_k^e\le n}d(p_k^e)(S_d(\lfloor\frac{i}{p_k^e}\rfloor,k)+[e>1]) \]

其中\(d(p_k^e)=(e+1)\)\(S_d\)仍然和正常的min_25一致。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7;
#define ll long long 
const ll md = 1145140019;
bool isp[maxn];
int tot, totw;
ll n, pri[maxn], idx1[maxn], idx2[maxn], T, w[maxn], g[maxn], sqrtn;
ll ksm(ll a, ll b) {
	ll res = 1;
	while (b) {
		if (b & 1) res = res * a % md;
		a = a * a % md;
		b >>= 1;
	}
	return res;
}
void sieve() {
	memset(isp, true, sizeof(isp));
	isp[1] = false;
	for (int i = 2; i <= 100000; i++) {
		if (isp[i]) {
			pri[++tot] = i;
		}
		for (int j = 1; j <= tot && i * pri[j] <= 100000; j++) {
			isp[i*pri[j]] = 0;
			if (i % pri[j] == 0) break;
		}
	}
}
typedef pair<ll, ll> pii;
pii S(ll i, ll j) {
	if (pri[j] > i) return (pii){0,0};
	int id = i > sqrtn ? idx2[n / i] : idx1[i];
	ll sp = (g[id] - j + md) % md, d = 2ll * sp % md;
	for (int k = j + 1; k <= tot && pri[k] * pri[k] <= i; k++) {
		for (ll p = pri[k], e = 1; p <= i; p *= pri[k], e++) {
			pii tmp = S(i / p, k);
			d = (d + (tmp.second + (e > 1)) * (e + 1)/*d(pre[k]^e), 合数部分*/ % md) % md;
			sp = (sp + (e+1)*tmp.first % md + e*(tmp.second + (e>1))%md)%md;
		}
	}
	return (pii){sp, d};
}
int main() {
	cin >> T;
	sieve();
	while (T--) {
		cin >> n;
		totw = 0;
		sqrtn = sqrt(n);
		for (ll l = 1, r; l <= n; l = r + 1) {
			ll k = n / l;
			r = n / k;
			w[++totw] = k;
			g[totw] = (k-1+md) % md;	
			if (k <= sqrtn) idx1[k] = totw;
			else idx2[r] = totw;
		}
		for (int i = 1; i <= tot; i++) {
			for (int j = 1; j <= totw && pri[i] * pri[i] <= w[j]; j++) {
				ll k = w[j] / pri[i];
				ll pre = k <= sqrtn ? idx1[k] : idx2[n/k];
				g[j] = (g[j] - 1ll * (g[pre] - (i - 1) + md) % md + md) % md;
			}
		}
		printf("%lld\n", S(n, 0).first);
	}		
}

注意空间开1e5会段错误,我也不知道为啥,,
update:整除分块的数有\(2\sqrt n\)个,要开2e5

posted @ 2021-08-12 15:09  yjmstr  阅读(115)  评论(0编辑  收藏  举报