2021牛客暑期多校训练营6 G Hasse Diagram(min25筛)

题目链接:点击这里

题目大意:
哈斯图,设 H n H_n Hn n n n 的因子组成的哈斯图,对于任意两个因子 u , v ( u > v ) u,v(u>v) u,v(u>v) u , v u,v u,v 之间有边当且仅当 u = p ⋅ v u=p·v u=pv

例如 H 12 H_{12} H12 如下图所示:
在这里插入图片描述
f ( x ) f(x) f(x) H x H_x Hx 的边数和,现在给定一个正整数 n n n ∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) i=1nf(i)

题目分析:
对于题目所求的 f ( x ) f(x) f(x) 有如下转移:
f ( x ) = { e x = p e ∑ i = 1 n ∑ e = 1 e i ( e + 1 ) ⋅ f ( x p i e ) + e ⋅ d ( x p i e ) x = ∏ p i e i f(x)=\begin{cases} e &x=p^e\\ \sum_{i=1}^n\sum_{e=1}^{e_i}(e+1)·f(\frac{x}{p_i^e})+e·d(\frac{x}{p_i^e}) &x=\prod p_i^{e_i} \end{cases} f(x)={ei=1ne=1ei(e+1)f(piex)+ed(piex)x=pex=piei

对于第二个递推式的理解: f ( x p e ) f(\frac{x}{p^e}) f(pex) 中的任意一条边 ( u , v ) (u,v) (u,v) 的两端可以乘上 p p p 1 1 1 e e e 次幂,可以得到 e e e 条新边,再由乘法原理算上 f ( x p e ) f(\frac{x}{p^e}) f(pex) 的贡献就是 ( e + 1 ) ⋅ f ( x p i e ) (e+1)·f(\frac{x}{p_i^e}) (e+1)f(piex) 。并且f(i/pe)的每个因子 a a a,都可以贡献 e e e 条形如 ( p e a , p e − 1 a ) (p^ea,p^{e-1}a) (pea,pe1a) 的边
由于 f ( p ) = 1 , d ( p ) = 2 f(p)=1,d(p)=2 f(p)=1,d(p)=2 ,所以我们取完全积性函数 F ( x ) = 1 F(x)=1 F(x)=1 m i n 25 min25 min25
我们知道下式是在 f ( x ) f(x) f(x) 是积性函数的情况下推出的:
S ( n , j ) = g ( n , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) + ∑ k = j + 1 p k 2 ≤ n ∑ e = 1 p k e ≤ n f ( p k e ) ( S ( ⌊ n p k e ⌋ , k ) + [ e > 1 ] ) S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{k=j+1}^{p_k^2\le n}\sum_{e=1}^{p^e_k\le n}f(p_k^e)(S(\lfloor \frac{n}{p_k^e} \rfloor,k)+[e>1]) S(n,j)=g(n,P)i=1j1f(pi)+k=j+1pk2ne=1pkenf(pke)(S(pken,k)+[e>1])
对于当前所求,我们需要同属维护 f ( x ) f(x) f(x) d ( x ) d(x) d(x) 两个函数,式子如下:
S ( n , j ) = g ( n , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) + ∑ k = j + 1 p k 2 ≤ n ∑ e = 1 p k e ≤ n ( ( e + 1 ) S ( ⌊ i p k e ⌋ , k ) + e ( ) S d ( ⌊ i p k e ⌋ , k ) + [ e > 1 ] ) S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{k=j+1}^{p_k^2\le n}\sum_{e=1}^{p^e_k\le n}((e+1)S(\lfloor \frac{i}{p_k^e} \rfloor,k)+e()S_d(\lfloor \frac{i}{p_k^e} \rfloor,k)+[e>1]) S(n,j)=g(n,P)i=1j1f(pi)+k=j+1pk2ne=1pken((e+1)S(pkei,k)+e()Sd(pkei,k)+[e>1])
S d ( n , j ) = 2 ( g ( n , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) ) + ∑ k = j + 1 p k 2 ≤ n ∑ e = 1 p k e ≤ n d ( p k e ) ( S d ( ⌊ n p k e ⌋ , k ) + [ e > 1 ] ) S_d(n,j)=2(g(n,|P|)-\sum_{i=1}^{j-1}f(p_i))+\sum_{k=j+1}^{p_k^2\le n}\sum_{e=1}^{p^e_k\le n}d(p_k^e)(S_d(\lfloor \frac{n}{p_k^e} \rfloor,k)+[e>1]) Sd(n,j)=2(g(n,P)i=1j1f(pi))+k=j+1pk2ne=1pkend(pke)(Sd(pken,k)+[e>1])

经验: m i n 25 min25 min25 筛可以通过筛积性函数前缀和来辅助计算非积性函数的前缀和

具体细节见代码:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
#define int  ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 1e6+5;
const int mod = 1145140019;
const double pi = acos(-1);
const double eps = 1e-8;
int n,cnt,pri[maxn],sq;
int w[maxn],tot,id1[maxn],id2[maxn],g1[maxn];
bool vis[maxn];
void get_pri(int n)
{
	for(int i = 2;i <= n;i++)
	{
		if(!vis[i])
		{
			pri[++cnt] = i;
		}
		for(int j = 1;j <= cnt && i*pri[j] <= n;j++)
		{
			vis[i*pri[j]] = true;
			if(i%pri[j] == 0) break;
		}
	}
}
int qpow(int a,int b)
{
	int res = 1;
	while(b)
	{
		if(b&1) res = res*a%mod;
		a = a*a%mod;
		b >>= 1;
	}
	return res;
}
const int inv2 = qpow(2,mod-2),inv6 = qpow(6,mod-2);
pair<int,int> S(int i,int j)
{
	if(pri[j] >= i) return {0,0};
	ll pos = i<=sq ? id1[i] : id2[n/i];
	ll res = (g1[pos]-j+mod)%mod;
	ll d = 2*res%mod;
	for(int k = j+1;k<=cnt && pri[k]*pri[k]<=i;k++) //合数部分贡献 
	{
		ll pe = pri[k];
		for(int e = 1;pe <= i;e++,pe = pe*pri[k]) //不能取模 
		{
			auto tmp = S(i/pe,k);
			d = (d+(tmp.second+(e>1))*(e+1)%mod)%mod;
			res = (res+(e+1)*tmp.first%mod+e*(tmp.second+(e>1))%mod)%mod;
		} 
	}
	return {res,d};
}
signed main()
{
	get_pri(1e6);
	int t = read();
	while(t--)
	{
		n = read(); sq = sqrt(n);
		tot = 0;
		for(int l = 1,r;l <= n;l = r+1)
		{
			r = min(n,n/(n/l));
			w[++tot] = n/l%mod; //取余方便计算下述的g(n,0) 
			g1[tot] = (w[tot]-1+mod)%mod; 
			w[tot] = n/l;
			if(w[tot] <= sq) id1[w[tot]] = tot;
			else id2[n/w[tot]] = tot;
		}
		for(int j = 1;j <= cnt;j++) //g(n,j)
			for(int i = 1;i<=tot && pri[j]*pri[j]<=w[i];i++)
			{
				ll tmp = w[i]/pri[j];
				ll pos = tmp <= sq ? id1[tmp] : id2[n/tmp];
				g1[i] = (g1[i]-(g1[pos]-(j-1)+mod)%mod+mod)%mod;
			}
		printf("%lld\n",(S(n,0).first)%mod);
	}
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值