题解:P8570 [JRKSJ R6] 牵连的世界
好纯粹的推柿子题啊,主要借鉴了 @littlez_meow 的题解,写得太好了,很清晰,但作为蒟蒻,我来说一下我的理解。
进入正题
首先,这两个函数的乘积一定是不好维护的,所以对这两个函数进行变形。
\varphi(ij)
证明:
考虑
因为每一个
\sigma_0(ij)
证明:
考虑把
若一个因数
证明:
因为已知
好了,推完这两个难搞的东西以后,就可以套用进题目给定的式子里面了,这里保证
变为:
前面改为枚举
经典套路要把
这个
此时,像合并同类项一般把两个
发现后两项属于同一形式,那记
好的,变得简洁多了,发现还有
现在,
此时,需要传入的数即为
终于好了,这是笔者第一次写这么大段的公式的题解,若有错误请指出,也请大家点点赞吧,上代码。
#include<bits/stdc++.h>
#define int long long
#define up(i,x,y) for(register int i=x;i<=y;i=-~i)
#define dn(i,y,x) for(register int i=y;i>=x;i--)
#define mst(x,y) memset(x,y,sizeof x)
#define D(x) cout<<#x<<": "<<x<<endl;
#define DE(x) cout<<#x<<": "<<x<<" ";
#define MAXSIZE 1<<21
// #define faster 1
#define pl p<<1
#define pr p<<1|1
using namespace std;
namespace lry{
char buf[MAXSIZE],*p1=buf,*p2=buf;
char pbuf[MAXSIZE],*pp=pbuf;
inline int gc(){
#if faster
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
#else
return getchar();
#endif
}
inline void pc(const char &c){
#if faster
if(pp-pbuf==MAXSIZE) fwrite(pbuf,1,MAXSIZE,stdout),pp=pbuf;*pp++=c;
#else
putchar(c);
#endif
}
inline bool blank(const char x){return !(x^32)||!(x^10)||!(x^13)||!(x^9);}
inline void read(double &rdx){double t=0;int x=0,s=0,f=1;char c;do c=gc();while(!isdigit(c)&&c!='-'&&c!='.');if (c=='-')f=-1,c=gc();while(isdigit(c)&&c!='.')x=(c^48)+(x<<1)+(x<<3),c=gc();if(c=='.')c=gc();else{rdx=x*f;return;}while(c>='0'&&c<='9')t=t*10+(c^48),s=-~s,c=gc();while(s--)t/=10;rdx=(x+t)*f;}
inline void read(string &x){x="";char a=gc();for(;blank(a)&&(a^-1);a=gc());for(;!blank(a)&&(a^-1);a=gc())x+=a;}
inline void read(char &x){char a=gc();for(;blank(a)&&(a^-1);a=gc());if(!blank(a)&&(a^-1))x=gc();}
inline void read(int &x){int ret=0,f=0;char ch=gc();while(!isdigit(ch)){if(ch=='-')f=1;ch=gc();}while(isdigit(ch)){ret=(ret<<1)+(ret<<3)+(ch^48);ch=gc();}x=(f?-ret:ret);}
template<typename t,typename ...T> inline void read(t &x,T&...y){read(x),read(y...);}
inline void write(int x){if(x<0)pc('-'),x=-x;if(x>9)write(x/10);pc(x%10+48);}
inline void write(const char *x){fputs(x,stdout);}
inline void write(const string &x){fputs(x.c_str(),stdout);}
inline void writeln(int x){write(x),pc('\n');}
inline void writetr(int x){write(x),pc(' ');}
inline void writeln(string x){write(x),pc('\n');}
inline void writetr(string x){write(x),pc(' ');}
template<typename t,typename ...T> inline void write(t x,T...y){write(x),write(y...);}
}
using namespace lry;
constexpr int N=3000000+10,inf=0x3f3f3f3f3f3f3f3f,mod=1000000007;
int prime[N],mu[N],phi[N],sum[N],num[N],cnt;
int tmp1[N],tmp2[N];
bool vis[N];
int n,m;
inline void init(){
mu[1]=phi[1]=sum[1]=1;
for(int i=2;i<N;i++){
if(!vis[i]) prime[++cnt]=i,mu[i]=-1,phi[i]=i-1,sum[i]=2,num[i]=1;
for(int j=1;j<=cnt&&i*prime[j]<N;j++){
vis[i*prime[j]]=1;
phi[i*prime[j]]=phi[i]*phi[prime[j]];
mu[i*prime[j]]=-mu[i];
num[i*prime[j]]=1;
sum[i*prime[j]]=sum[i]*2;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
mu[i*prime[j]]=0;
num[i*prime[j]]=num[i]+1;
sum[i*prime[j]]=sum[i]/(num[i]+1)*(num[i*prime[j]]+1);
break;
}
}
}
}
inline int ksm(int x,int a){
int mul=1;
while(a){
if(a&1) mul=mul*x%mod;
x=x*x%mod; a>>=1;
}
return mul;
}
signed main(){
init();
read(n,m);
if(n>m) swap(n,m);
int ans=0;
for(int r=1;r<=n;r++){
if(!mu[r]) continue;
for(int d=1;d<=n/r;d++){
tmp1[d]=tmp2[d]=0;
for(int k=1;k<=n/d/r;k++) tmp1[d]=(tmp1[d]+phi[r*d*k]*sum[d*k]%mod)%mod;
for(int k=1;k<=m/d/r;k++) tmp2[d]=(tmp2[d]+phi[r*d*k]*sum[d*k]%mod)%mod;
}
for(int d=1;d<=n/r;d++){
int inv=ksm(phi[d*r],mod-2);
for(int k=1;k<=n/d/r;k++){
ans=(ans+mu[r]*r%mod*d%mod*inv%mod*mu[k]%mod*tmp1[k*d]%mod*tmp2[k*d]%mod+mod)%mod;
}
}
}
writeln(ans);
#if faster
fwrite(pbuf,1,pp-pbuf,stdout);
pp=pbuf;
#endif
return 0;
}