7.12 NOI模拟赛 积性函数求和 数论基础变换 莫比乌斯反演

avatar
avatar

神题!

一眼powerful number 复习了一下+推半天。

可以发现G函数只能为\(\sum_{d}[d|x]d\)

不断的推 可以发现最后需要求很多块G函数的前缀和 发现只有\(\sqrt(n)\)的复杂度。

于是自闭了。不过这个做法可以跑过\(1e9\) 第二个subtask没有那么严格所以可以跑过 不过我CE了2333...

也没考虑\(min_25\)筛 可能学的不太精通。。

正解是发现 \(f(n)=(p^{k1}+1)(p^{k2}+1)...\)

然后 将其展开 求每个数字对n的贡献 即枚举上述状态的每一项.

那么在求前缀和中i可以被统计到答案中的标志为存在令一个数字j 满足\(i\cdot j\leq n\)\((i,j)=1\)

那么其实答案为 \(\sum_{i=1}^n\sum_{j=1}^{\frac{n}{i}}[(i,j)=1]i\)

莫比乌斯反演一下可以得到.

\(\sum_{x=1}^n\mu(x)\sum_{i=1}^{\frac{n}{x}}i\frac{n}{i\cdot x^2}\)

这其实就可以做了。

考虑到\(\frac{n}{i\cdot x^2}\)有值 那么显然 \(x\leq \sqrt n\)

\(i\leq \frac{n}{x^2}\)

那么上述式子枚举范围可以变一下.\(\sum_{x=1}^{\sqrt n}\mu(x)\sum_{i=1}^{\frac{n}{x^2}}i\frac{n}{i\cdot x^2}\)

左边暴力枚举 右边整除分块。可以证明这样复杂度为\(\sqrt n\cdot logn\)

可能有点卡常 考虑线性筛出 \(d_n\)表示\(\sum_{i=1}^{n}i\frac{n}{i}\)

考虑右边的实际意义 约数和的前缀和 那么只需要筛出每个数字约数和 再前缀和一下即可。

code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(ll i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE ll i=n;i>=p;--i)
#define vep(p,n,i) for(RE ll i=p;i<n;++i)
#define pii pair<ll,ll>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-4
#define sq sqrt
#define S second
#define F first
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    RE ll x=0,f=1;RE char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const ll MAXN=4000010;
ll n;
int m,mod,top,INV2;
int p[MAXN],mu[MAXN],v[MAXN],g[MAXN],w[MAXN];
inline void prepare()
{
	mu[1]=g[1]=1;
	rep(2,m,i)
	{
		if(!v[i])v[i]=p[++top]=i,w[i]=i,mu[i]=-1;
		if(w[i]==i)g[i]=(g[i/v[i]]+i)%mod;
		else g[i]=(ll)g[i/w[i]]*g[w[i]]%mod;
		rep(1,top,j)
		{
			if(p[j]>m/i)break;
			v[p[j]*i]=p[j];
			if(v[i]==p[j])
			{
				w[p[j]*i]=w[i]*p[j];
				break;
			}
			w[p[j]*i]=p[j];mu[p[j]*i]=-mu[i];
		}
	}
	rep(1,m,i)g[i]=(g[i-1]+g[i])%mod;
}
inline int solve(ll n)
{
	if(n<=m)return g[n]*2%mod;
	if(n>=mod)
	{
		ll ww,w1;
		int ans=0;
		for(ll i=1;i<=n;i=ww+1)
		{
			w1=n/i;ww=n/w1;
			ans=(ans+(i+ww)%mod*((ww-i+1)%mod)%mod*(w1%mod))%mod;
		}
		return ans;
	}
	else
	{
		ll ww,w1;
		int ans=0;
		for(ll i=1;i<=n;i=ww+1)
		{
			w1=n/i;ww=n/w1;
			ans=(ans+(i+ww)*(ww-i+1)%mod*w1)%mod;
		}
		return ans;
	}
}
signed main()
{
	freopen("1.in","r",stdin);
	get(n);get(mod);m=(int)sqrt(n*1.0);INV2=(1+mod)>>1;
	prepare();int ans=0;
	rep(1,m,i)if(mu[i])ans=(ans+mu[i]*(ll)i*solve(n/i/i))%mod;
	ans=(ans+mod)%mod;put((ll)ans*INV2%mod);return 0;
}
posted @ 2020-07-12 22:36  chdy  阅读(167)  评论(0编辑  收藏  举报