题目描述:
求:
∑
d
∣
n
,
d
∣
s
∑
g
∣
n
d
μ
(
g
)
∗
⌊
m
d
g
⌋
\sum_{d|n,d|s}\sum_{g|\frac nd}\mu(g)*\lfloor\frac m{dg}\rfloor
d∣n,d∣s∑g∣dn∑μ(g)∗⌊dgm⌋
其中
n
,
m
,
s
n,m,s
n,m,s满足
{
n
=
n
1
⋅
n
2
⋅
n
3
m
=
m
1
⋅
m
2
⋅
m
3
s
=
s
1
⋅
s
2
⋅
s
3
\begin{cases}n=n_1\cdot n_2\cdot n_3\\m=m_1\cdot m_2\cdot m_3\\s=s_1\cdot s_2\cdot s_3\end{cases}
⎩⎪⎨⎪⎧n=n1⋅n2⋅n3m=m1⋅m2⋅m3s=s1⋅s2⋅s3
多组数据,数据组数
≤
1000
\le1000
≤1000,
n
1
,
n
2
,
n
3
,
m
1
,
m
2
,
m
3
,
s
1
,
s
2
,
s
3
≤
1
0
6
n_1,n_2,n_3,m_1,m_2,m_3,s_1,s_2,s_3\le10^6
n1,n2,n3,m1,m2,m3,s1,s2,s3≤106
题目分析:
看到这个东西并且联想到NOIP的标题以及yali标准的模拟赛样式就明白这一定是把莫比乌斯反演的式子推到某一步进行了奇奇怪怪的变换然后拿来恶心人防AK。
于是我们开始按照题解推式子:
∑
d
∣
n
,
d
∣
s
∑
g
∣
n
d
μ
(
g
)
∗
⌊
m
d
g
⌋
\sum_{d|n,d|s}\sum_{g|\frac nd}\mu(g)*\lfloor\frac m{dg}\rfloor
d∣n,d∣s∑g∣dn∑μ(g)∗⌊dgm⌋
首先把
μ
\mu
μ函数的系数想办法搞掉:
∑
d
∣
n
,
d
∣
s
∑
g
∣
n
d
∑
i
=
1
⌊
m
d
g
⌋
μ
(
g
)
\sum_{d|n,d|s}\sum_{g|\frac nd}\sum_{i=1}^{\lfloor\frac m{dg}\rfloor}\mu(g)
d∣n,d∣s∑g∣dn∑i=1∑⌊dgm⌋μ(g)
联想到
∑
g
∣
k
μ
(
g
)
=
[
k
=
1
]
\sum_{g|k}\mu(g)=[k=1]
∑g∣kμ(g)=[k=1],把第二个∑放到里层,原来的后两式相当于枚举
⌊
m
d
⌋
{\lfloor\frac m{d}\rfloor}
⌊dm⌋中g的倍数,转换一下可变为:
∑
d
∣
n
,
d
∣
s
∑
i
=
1
⌊
m
d
⌋
∑
g
∣
n
d
,
g
∣
i
μ
(
g
)
\sum_{d|n,d|s}\sum_{i=1}^{\lfloor\frac m{d}\rfloor}\sum_{g|\frac nd,g|i}\mu(g)
d∣n,d∣s∑i=1∑⌊dm⌋g∣dn,g∣i∑μ(g)
整除两个数就相当于整除它们的gcd,于是:
∑
d
∣
n
,
d
∣
s
∑
i
=
1
⌊
m
d
⌋
[
g
c
d
(
i
,
n
d
)
=
1
]
\sum_{d|n,d|s}\sum_{i=1}^{\lfloor\frac m{d}\rfloor}[gcd(i,\frac nd)=1]
d∣n,d∣s∑i=1∑⌊dm⌋[gcd(i,dn)=1]
先不看
d
∣
s
d|s
d∣s的条件,观察式子,发现其实
d
d
d就是在枚举
[
1
,
m
]
[1,m]
[1,m]中的数与
n
n
n的
g
c
d
gcd
gcd,如果没有
d
∣
s
d|s
d∣s的条件,则式子就
=
m
=m
=m
现在加上
d
∣
s
d|s
d∣s的条件,那么只有与
n
n
n的
g
c
d
gcd
gcd为
s
s
s的约数的数会被统计到,即:
∑
i
=
1
m
[
g
c
d
(
i
,
n
)
∣
s
]
\sum_{i=1}^{m}[gcd(i,n)|s]
i=1∑m[gcd(i,n)∣s]
到这里可以
O
(
m
log
m
)
O(m\log m)
O(mlogm)枚举计算,结合部分分拿到70分。
Code:
#include<bits/stdc++.h>
#define LL long long
#define x first
#define y second
using namespace std;
int T,num,bit[1<<15];
LL n,m,s,ans,f[1<<15];
vector<pair<int,int> >a,b;
void Divide(int x,vector<pair<int,int> >&q){
for(int i=q.size()-1;i>=0;i--) while(x%q[i].x==0) q[i].y++,x/=q[i].x;
for(int i=2;i*i<=x;i++) if(x%i==0){
q.push_back(make_pair(i,0));
while(x%i==0) q.back().y++,x/=i;
}
if(x>1) q.push_back(make_pair(x,1));
}
int main()
{
//freopen("c.in","r",stdin);
//freopen("c.out","w",stdout);
scanf("%d",&T);
while(T--){
n=m=s=1,ans=num=0,a.clear(),b.clear();
for(int i=0,x;i<3;i++) scanf("%d",&x),Divide(x,a);
for(int i=0,x;i<3;i++) scanf("%d",&x),m*=x;
for(int i=0,x;i<3;i++) scanf("%d",&x),Divide(x,b);
sort(a.begin(),a.end()),sort(b.begin(),b.end());
for(int i=0,j=0;i<a.size();i++){
while(j<b.size()&&b[j].x<a[i].x) j++;
if(j==b.size()||b[j].x>a[i].x||b[j].y<a[i].y){
f[1<<num]=a[i].x;int ed=j==b.size()||b[j].x>a[i].x?0:b[j].y;
for(int k=1;k<=ed;k++) f[1<<num]*=a[i].x;
num++;
}
}
ans=m,f[0]=1;
for(int s=1;s<1<<num;s++){
bit[s]=bit[s>>1]+(s&1);
f[s]=f[s^(s&-s)]*f[s&-s];
ans+=(bit[s]&1?-1:1)*m/f[s];
}
printf("%lld\n",ans);
}
}