51nod 1584 加权约数和 约数和函数小trick 莫比乌斯反演

LINK:加权约数和

我曾经一度认为莫比乌斯反演都是板子题.

做过这道题我认输了 不是什么东西都是板子.

一个trick 设\(s(x)\)为x的约数和函数.

\(s(i\cdot j)=\sum_{x|i}\sum_{y|j}[(x,y)==1]x\cdot \frac{j}{y}\)

证明的话可以自己意会 赶时间.

然后 这道题唯一特别的是转换完后 直接莽推根号做法是行不通的 同时也过不去.

不如先考虑求 \(f_i=\sum_{j=1}^i s(i\cdot j)\)

然后带入上面的那个trick 莫比乌斯反演一波 发现什么都得不到.

此时 配合上面trick的转换是 \(f_i=\sum_{j=1}^i\sum_{x|j,x|i}\mu(x)\sum_{u|i,x|u}\sum_{v|j,x|v}u\frac{j}{v}\)

绝妙或者是套路的转换为 \(f_i=\sum_{j=1}^i\sum_{x|j,x|i}\mu(x)s(x\cdot s(\frac{i}{x}))s(\frac{j}{x})\)

下面颠倒求和即可.

然后就可以做了 复杂度 \(nlnn+T\)

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#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 1000000000000000000ll
#define inf 100000000000000000ll
#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 rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-10
#define sq sqrt
#define S second
#define F first
#define mod 1000000007
#define max(x,y) ((x)<(y)?y:x)
using namespace std;
char *fs,*ft,buf[1<<15];
inline char gc()
{
	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
	RE int x=0,f=1;RE char ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
	return x*f;
}
const int MAXN=1000010;
int n,T,top;
int v[MAXN],p[MAXN],d[MAXN],sum[MAXN],D[MAXN],w[MAXN],f[MAXN],in[MAXN],mu[MAXN];
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int mul(int x,int y){return (ll)x*y%mod;}
inline int mus(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int ksm(int b,int p)
{
	int cnt=1;
	while(p)
	{
		if(p&1)cnt=mul(cnt,b);
		b=mul(b,b);p=p>>1;
	}
	return cnt;
}
inline void prepare()
{
	sum[1]=mu[1]=in[1]=d[1]=D[1]=1;
	rep(2,n,i)
	{
		in[i]=mul(in[mod%i],(mod-mod/i));
		if(!v[i])
		{
			v[i]=p[++top]=i;mu[i]=-1;
			w[i]=p[top];d[i]=i+1;
			D[i]=add(1+i,(ll)i*i%mod);
		}
		sum[i]=add(d[i],sum[i-1]);
		rep(1,top,j)
		{
			if(p[j]>n/i)break;
			int ww=p[j]*i;
			v[ww]=p[j];
			if(v[i]==p[j])
			{
				w[ww]=w[i]*p[j];
				if(w[ww]==ww)
				{
					d[ww]=add(d[i],ww);
					D[ww]=add(D[i],add((ll)ww*ww%mod,(ll)i*i%mod*p[j]%mod));
				}
				else 
				{
					d[ww]=mul(d[i/w[i]],d[w[ww]]);
					D[ww]=mul(D[i/w[i]],D[w[ww]]);
				}
				break;
			}
			w[ww]=p[j];d[ww]=mul(d[i],d[p[j]]);
			D[ww]=mul(D[i],D[p[j]]);
			mu[ww]=-mu[i];
		}
	}
	/*rep(1,1000,i)
	{
		if(D[i]!=d[i*i])
		{
			cout<<"ww"<<endl;
			cout<<i<<endl;
			return;
		}
	}*/
	rep(1,n,i)
	{
		if(mu[i])
		{
			for(int j=i;j<=n;j+=i)
			f[j]=(f[j]+mu[i]*(ll)i*d[j/i]%mod*sum[j/i])%mod;
		}
		f[i]=((mul(f[i],2*i)-mul(i,D[i]))%mod+mod)%mod;
		f[i]=add(f[i],f[i-1]);
	}
}
signed main()
{
	//freopen("1.in","r",stdin);
	n=1000000;prepare();
	get(T);
	rep(1,T,W)
	{
		printf("Case #%d: ",W);	
		put(f[read()]);
	}
	return 0;
}
posted @ 2020-07-27 20:39  chdy  阅读(103)  评论(0编辑  收藏  举报