Description
旧试题
skyfall
约数个数和
由于这三个题长得比较像就放一起吧
设 D ( u ) D(u) D(u)表示 u u u的约数和,那么有如下结论
D ( x ∗ y ) = ∑ u ∣ x ∑ v ∣ y [ g c d ( u , v ) = = 1 ] D(x*y)=\sum_{u|x}\sum_{v|y} [gcd(u,v)==1] D(x∗y)=u∣x∑v∣y∑[gcd(u,v)==1]
证明如下,设 k i k_i ki表示质因数 p i p_i pi在某个数中的次数
显然约数个数和为 Π ( k i + 1 ) \Pi(k_i+1) Π(ki+1)
显然可以知道, x ∗ y x*y x∗y中的某个 k i k_i ki一定是在 x x x中贡献了 u i u_i ui,在 y y y中贡献了 v i v_i vi并且满足 u i + v i = k + i u_i+v_i=k+i ui+vi=k+i的。那么对于上式,由于 g c d ( u , v ) = 1 gcd(u,v)=1 gcd(u,v)=1,故在 x ∗ y x*y x∗y的某个质因数 p i p_i pi中,仅存在三种情况
该质因数被 u u u取走,有 u i u_i ui种取的次数,该质因数被 v v v取走,有 v i v_i vi种取的次数,或者两者均不取,有 1 1 1的次数,则该质因数的合法取法有 u i + v i + 1 = k i + 1 u_i+v_i+1=k_i+1 ui+vi+1=ki+1种,相乘即为约数个数和
拓展到更高维也是一样的
那么式子可以写为
以下均视为 n ≤ m n\leq m n≤m
∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = 1 ] ⌊ n i ⌋ ⌊ m j ⌋ \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1]\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{j}\rfloor i=1∑nj=1∑m[gcd(i,j)==1]⌊in⌋⌊jm⌋
随意反演一下就可以得到,
∑ d = 1 n μ ( d ) ∗ ∑ i = 1 ⌊ n d ⌋ ⌊ n i ∗ d ⌋ ∗ ∑ j = 1 ⌊ m d ⌋ ⌊ m j ∗ d ⌋ \sum_{d=1}^{n}\mu(d)*\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{i*d}\rfloor*\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{j*d}\rfloor d=1∑nμ(d)∗i=1∑⌊dn⌋⌊i∗dn⌋∗j=1∑⌊dm⌋⌊j∗dm⌋
注意到有式子 ⌊ n i ∗ j ⌋ = ⌊ ⌊ n i ⌋ j ⌋ \lfloor\frac{n}{i*j}\rfloor=\lfloor\frac{\lfloor\frac{n}{i}\rfloor}{j}\rfloor ⌊i∗jn⌋=⌊j⌊in⌋⌋
故上式可写为
∑ d = 1 n μ ( d ) ∗ ∑ i = 1 ⌊ n d ⌋ ⌊ ⌊ n d ⌋ i ⌋ ∗ ∑ j = 1 ⌊ m d ⌋ ⌊ m d ⌋ i ⌋ \sum_{d=1}^{n}\mu(d)*\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{\lfloor\frac{n}{d}\rfloor}{i}\rfloor*\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\frac{\lfloor\frac{m}{d}\rfloor}{i}\rfloor d=1∑nμ(d)∗i=1∑⌊dn⌋⌊i⌊dn⌋⌋∗j=1∑⌊dm⌋i⌊dm⌋⌋
我写这个的时候没有及时意识到把 d d d提上去然后自闭了一会…
n n n\sqrt n nn预处理一个 f ( i ) = ∑ j = 1 i ⌊ i j ⌋ f(i)=\sum_{j=1}^{i} \lfloor\frac{i}{j}\rfloor f(i)=∑j=1i⌊ji⌋
剩下就可以 T ∗ ( n + m ) T*(\sqrt n+\sqrt m) T∗(n+m)了
与上一个题式子基本是相同的
在开头枚举一下 c c c就可以获得一个 n 2 log n n^2\log n n2logn的做法了
式子是
∑ k = 1 c ⌊ c k ⌋ ∗ ∑ d = 1 a μ ( d ) ∗ ∑ i = 1 ⌊ a d ⌋ ⌊ a i ∗ d ⌋ ∗ [ g c d ( a d , k ) = = 1 ] ∗ ∑ j = 1 ⌊ b d ⌋ ⌊ b j ∗ d ⌋ ∗ [ g c d ( b d , k ) = = 1 ] \sum_{k=1}^{c}\lfloor \frac{c}{k}\rfloor*\sum_{d=1}^{a}\mu(d)*\sum_{i=1}^{\lfloor\frac{a}{d}\rfloor}\lfloor\frac{a}{i*d}\rfloor*[gcd(ad,k)==1]*\sum_{j=1}^{\lfloor\frac{b}{d}\rfloor}\lfloor\frac{b}{j*d}\rfloor*[gcd(bd,k)==1] k=1∑c⌊kc⌋∗d=1∑aμ(d)∗i=1∑⌊da⌋⌊i∗da⌋∗[gcd(ad,k)==1]∗j=1∑⌊db⌋⌊j∗db⌋∗[gcd(bd,k)==1]
可以直接做了
听说需要卡常
上面都太naive了啊.
这才是最终的哥哥题
同样运用上面的结论,式子化一下就可以得到
∑ d a = 1 m a x ( a , b , c ) ∑ d b = 1 m a x ( a , b , c ) ∑ d c = 1 m a x ( a , b , c ) μ ( a ) μ ( b ) μ ( c ) ∗ ∑ i ∣ l c m ( d a , d b ) ⌊ a i ⌋ ∗ ∑ j ∣ l c m ( d b , d c ) ⌊ b j ⌋ ∗ ∑ k ∣ l c m ( d a , d c ) ⌊ c k ⌋ \sum_{da=1}^{max(a,b,c)}\sum_{db=1}^{max(a,b,c)}\sum_{dc=1}^{max(a,b,c)}\mu(a)\mu(b)\mu(c)*\sum_{i|lcm(da,db)}\lfloor\frac{a}{i}\rfloor*\sum_{j|lcm(db,dc)}\lfloor\frac{b}{j}\rfloor*\sum_{k|lcm(da,dc)}\lfloor\frac{c}{k}\rfloor da=1∑max(a,b,c)db=1∑max(a,b,c)dc=1∑max(a,b,c)μ(a)μ(b)μ(c)∗i∣lcm(da,db)∑⌊ia⌋∗j∣lcm(db,dc)∑⌊jb⌋∗k∣lcm(da,dc)∑⌊kc⌋
前面是枚举约数的,用原式换过去不难得到
后面显然可以 n l o g n nlogn nlogn直接预处理出来
于是我们考虑怎么算前面合法的 a , b , c a,b,c a,b,c的贡献
首先,显然合法的 a , b , c a,b,c a,b,c需要满足任意两个数之间的 l c m ≤ max ( a , b , c ) lcm\leq \max(a,b,c) lcm≤max(a,b,c)
下文不妨设 n = m a x ( a , b , c ) n=max(a,b,c) n=max(a,b,c)
如果我们给两个合法的数对连上无向边,显然能做出贡献的就是图中的三元环
数三元环的数量是可以做到 m m m\sqrt m mm的,其中 m m m为边数证明不会
先介绍如何做到 m m m\sqrt m mm
我们将边定向,满足任意一条边都是从度数较小的点出去,进入度数较大的点
接下来枚举所有点计数,我们发现,原图中存在的任意一个三元环 ( x , y , c ) (x,y,c) (x,y,c)。不妨假定 i n [ x ] ≤ i n [ y ] ≤ i n [ z ] in[x]\leq in[y]\leq in[z] in[x]≤in[y]≤in[z],在新图中一定满足存在 x − > y − > z x->y->z x−>y−>z与 x − > z x->z x−>z的路径
故直接枚举第一条路径的两个点判断即可
注意这里的三元环是有顺序的,我们需要做到无序,故要将其六种情况全部讨论一遍
再来建图
枚举有边相连的两个点的 g c d gcd gcd,剩余要求互质。
求解过程则是简单问题
注意边用vector存,可以大幅优化常数
但是忽略了两种情况,即选了三个同样的点或者两个同样的点
选三个点时可以直接预处理,选两个点时可以在建边的过程做出来
复杂度估计是不存在的?
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair
#define pii pair
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){
putchar('-');x=-x;}
if(!x){
putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){
write(x);putchar(' ');}
inline void pr2(int x){
write(x);putchar('\n');}
const int MAXN=100005;
const int mod=1e9+7;
struct edge
{
int x,y,c;
edge(){
}
edge(int _x,int _y,int _c){
x=_x;y=_y;c=_c;}
};
vector<pii> vec[MAXN];
vector<edge> vec1;
int mu[MAXN],pr[MAXN],plen;
bool is[MAXN];
void getmu(int N)
{
mu[1]=1;
for(int i=2;i<=N;i++)
{
if(!is[i])mu[i]=-1,pr[++plen]=i;
for(int j=1;i*pr[j]<=N&&j<=plen;j++)
{
is[i*pr[j]]=true;
if(!(i%pr[j]))mu[i*pr[j]]=0;
else mu[i*pr[j]]=-mu[i];
}
}
}
int A,B,C,n,m;
LL ans;
LL fa[MAXN],fb[MAXN],fc[MAXN];
void getf(LL *y,int len)
{
for(int i=1;i<=len;i++)for(int j=1;i*j<=len;j++)y[i]+=len/(i*j);
for(int i=1;i<=len;i++)y[i]%=mod;
}
void work1(){
for(int i=1;i<=m;i++)ans+=fa[i]*fb[i]*fc[i]*mu[i]*mu[i]*mu[i]%mod;}
int du[MAXN];
int gcd(int a,int b){
return a==0?b:gcd(b%a,a);}
void prering()
{
vec1.clear();
memset(du,0,sizeof(du));
for(int GCD=1;GCD<=n;GCD++)for(int u1=1;u1*GCD<=n;u1++)if(mu[u1*GCD])
for(int u2=u1+1;1LL*u2*u1*GCD<=n;u2++)
if(gcd(u1,u2)==1&&mu[u2*GCD])
{
int x=u1*GCD,y=u2*GCD,lcm=u1*u2*GCD;
// if(lcm>n)continue;
ans+=mu[x]*mu[x]*mu[y]*(fa[x]*fb[lcm]*fc[lcm]+fa[lcm]*fb[x]*fc[lcm]+fa[lcm]*fb[lcm]*fc[x]);
ans+=mu[x]*mu[y]*mu[y]*(fa[y]*fb[lcm]*fc[lcm]+fa[lcm]*fb[y]*fc[lcm]+fa[lcm]*fb[lcm]*fc[y]);
vec1.push_back(edge(x,y,lcm));
du[x]++;du[y]++;
}
for(int i=0;i<vec1.size();i++)
{
int x=vec1[i].x,y=vec1[i].y,lcm=vec1[i].c;
if(du[x]<du[y])vec[x].push_back(mp(y,lcm));
else vec[y].push_back(mp(x,lcm));
}
}
int nxt[MAXN],lm[MAXN],tim;
void solve()
{
for(int i=1;i<=n;i++)if(mu[i])
{
tim++;
for(int j=0;j<vec[i].size();j++)nxt[vec[i][j].first]=tim,lm[vec[i][j].first]=vec[i][j].second;
for(int j=0;j<vec[i].size();j++)
{
int y=vec[i][j].first;
for(int k=0;k<vec[y].size();k++)
{
int z=vec[y][k].first;
if(nxt[z]!=tim)continue;
int x=i;
int lm1=vec[i][j].second,lm2=vec[y][k].second,lm3=lm[z],mul=mu[x]*mu[y]*mu[z];
ans+=mul*(fa[lm1]*fb[lm2]*fc[lm3]+fa[lm1]*fb[lm3]*fc[lm2]+fa[lm2]*fb[lm1]*fc[lm3]+fa[lm2]*fb[lm3]*fc[lm1]+fa[lm3]*fb[lm1]*fc[lm2]+fa[lm3]*fb[lm2]*fc[lm1]);
}
}
}
}
int main()
{
getmu(MAXN-1);
int T=read();while(T--)
{
for(int i=1;i<=n;i++)vec[i].clear();
A=read();B=read();C=read();ans=0;
memset(fa,0,sizeof(fa));memset(fb,0,sizeof(fb));memset(fc,0,sizeof(fc));
getf(fa,A);getf(fb,B);getf(fc,C);
n=max(A,max(B,C));m=min(A,min(B,C));
memset(nxt,0,sizeof(nxt));tim=0;
work1();
prering();
solve();
pr2((ans%mod+mod)%mod);
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair
#define pii pair
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){
putchar('-');x=-x;}
if(!x){
putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){
write(x);putchar(' ');}
inline void pr2(LL x){
write(x);putchar('\n');}
const int MAXN=50005;
int mu[MAXN],pr[MAXN],plen;
bool is[MAXN];
void getpr(int N)
{
mu[1]=1;
for(int i=2;i<=N;i++)
{
if(!is[i])mu[i]=-1,pr[++plen]=i;
for(int j=1;i*pr[j]<=N&&j<=plen;j++)
{
is[i*pr[j]]=true;
if(!(i%pr[j]))mu[i*pr[j]]=0;
else mu[i*pr[j]]=-mu[i];
}
}
for(int i=2;i<=N;i++)mu[i]+=mu[i-1];
}
LL f[MAXN];
int main()
{
getpr(MAXN-1);
for(int i=1;i<MAXN;i++)
for(int j=1,nxt;j<=i;j=nxt+1)
{
nxt=i/(i/j);
f[i]+=1LL*(nxt-j+1)*(i/j);
}
int T=read();while(T--)
{
int n=read(),m=read();
if(n>m)swap(n,m);
LL ans=0;
for(int i=1,nxt;i<=n;i=nxt+1)
{
nxt=min(n/(n/i),m/(m/i));
ans+=1LL*(mu[nxt]-mu[i-1])*f[n/i]*f[m/i];
}
pr2(ans);
}
return 0;
}