51nod 1584 加權約數和 約數和函式小trick 莫比烏斯反演
阿新 • • 發佈:2020-07-27
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; }