欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
先%一波dalao——PoPoQQQ
话说这道题真的毒瘤啊!
一句话题意,设 f ( i ) f(i) f(i)为 i i i的约数和,求 a n s = ∑ i = 1 n ∑ j = 1 m 并 且 f ( gcd ( i , j ) ) < = a f ( gcd ( i , j ) ) mod 2 31 \large ans=\sum_{i=1}^n\sum_{j=1}^{m并且f(\gcd(i,j))<=a}f(\gcd(i,j))\operatorname{mod}2^{31} ans=i=1∑nj=1∑m并且f(gcd(i,j))<=af(gcd(i,j))mod231
假设现在先无 a a a这个限制条件。
由Zap(务必看一看)可知,
1
≤
i
≤
n
,
1
≤
j
≤
n
,
gcd
(
i
,
j
)
=
k
1\le i\le n,1\le j\le n,\gcd(i,j)=k
1≤i≤n,1≤j≤n,gcd(i,j)=k可以转化为
1
≤
i
≤
n
/
k
,
1
≤
j
≤
n
,
gcd
(
i
,
j
)
=
1
1\le i\le n/k,1\le j\le n,\gcd(i,j)=1
1≤i≤n/k,1≤j≤n,gcd(i,j)=1,我们设
g
(
i
)
g(i)
g(i)表示满足
x
≤
n
,
y
≤
m
x\le n,y\le m
x≤n,y≤m并且
gcd
(
x
,
y
)
=
i
\gcd(x,y)=i
gcd(x,y)=i的二元组有多少对,显然
g
(
i
)
=
F
(
⌊
n
/
i
⌋
,
⌊
m
/
i
⌋
)
=
∑
j
=
1
min
(
⌊
n
/
i
⌋
,
⌊
m
/
i
⌋
)
μ
(
j
)
∗
D
(
⌊
n
/
i
⌋
,
⌊
m
/
i
⌋
,
j
)
\large g(i)=F(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor)=\sum_{j=1}^{\min(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor)}\mu(j)*D(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor,j)
g(i)=F(⌊n/i⌋,⌊m/i⌋)=j=1∑min(⌊n/i⌋,⌊m/i⌋)μ(j)∗D(⌊n/i⌋,⌊m/i⌋,j)
g
(
i
)
=
∑
j
=
1
min
(
⌊
n
/
i
⌋
,
⌊
m
/
i
⌋
)
μ
(
j
)
∗
⌊
⌊
n
/
i
⌋
/
j
⌋
∗
⌊
⌊
m
/
i
⌋
/
j
⌋
\large g(i)=\sum_{j=1}^{\min(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor)}\mu(j)*\left\lfloor\\ \left\lfloor\\n/i\right\rfloor/j\right\rfloor*\left\lfloor\\ \left\lfloor\\m/i\right\rfloor/j\right\rfloor
g(i)=j=1∑min(⌊n/i⌋,⌊m/i⌋)μ(j)∗⌊⌊n/i⌋/j⌋∗⌊⌊m/i⌋/j⌋
令
d
=
i
∗
j
d=i*j
d=i∗j,有
g
(
i
)
=
∑
i
∣
d
min
(
n
,
m
)
μ
(
d
i
)
∗
⌊
n
/
d
⌋
∗
⌊
m
/
d
⌋
\large g(i)=\sum_{i|d}^{\min(n,m)}\mu(\frac{d}{i})*\left\lfloor\\ n/d\right\rfloor*\left\lfloor\\ m/d\right\rfloor
g(i)=i∣d∑min(n,m)μ(id)∗⌊n/d⌋∗⌊m/d⌋
所以 a n s = ∑ i = 1 m i n ( n , m ) g ( i ) f ( i ) = ∑ i = 1 m i n ( n , m ) ∑ i ∣ d min ( n , m ) μ ( d i ) ∗ ⌊ n / d ⌋ ∗ ⌊ m / d ⌋ ∗ f ( i ) \large ans=\sum_{i=1}^{min(n,m)}g(i)f(i)=\sum_{i=1}^{min(n,m)}\sum_{i|d}^{\min(n,m)}\mu(\frac{d}{i})*\left\lfloor\\ n/d\right\rfloor*\left\lfloor\\ m/d\right\rfloor* f(i) ans=i=1∑min(n,m)g(i)f(i)=i=1∑min(n,m)i∣d∑min(n,m)μ(id)∗⌊n/d⌋∗⌊m/d⌋∗f(i)
= ∑ d = 1 min ( n , m ) ⌊ n / d ⌋ ∗ ⌊ m / d ⌋ ∑ i ∣ d m i n ( n , m ) μ ( d i ) ∗ f ( i ) =\large\sum_{d=1}^{\min(n,m)}\left\lfloor\\ n/d\right\rfloor*\left\lfloor\\ m/d\right\rfloor\sum_{i\mid d}^{min(n,m)}\mu(\frac{d}{i})*f(i) =d=1∑min(n,m)⌊n/d⌋∗⌊m/d⌋i∣d∑min(n,m)μ(id)∗f(i)
预先处理一下, f ( i ) f(i) f(i)数组。
所以没有限制条件 a a a下的答案,就如上所求。
我们只要排序一下 a a a就行了。
那么有限制条件 a a a时,我们要多开一个树状数组,并将 f ( i ) f(i) f(i)排序。
每次询问时,进行相应操作即可。
AC code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define gc getchar()
using namespace std;
const int M=4e4+10;
const int N=1e5+10;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
int Q,mx,m;
struct data{int n,m,a,id;}q[M];int ans[M];
bool v[N];int prime[N],mu[N],c[N];
bool cmp1(data a,data b){return a.a<b.a;}
struct node{int sum,id;}f[N];
bool cmp2(node a,node b){return a.sum<b.sum;}
void add(int x,int y){for(;x<=mx;x+=x&-x)c[x]+=y;}
int ask(int x)
{
int tmp=0;
for(;x;x-=x&-x)tmp+=c[x];
return tmp;
}
void pre()
{
mu[1]=1;m=0;
for(int i=2;i<=mx;i++)
{
if(!v[i])prime[++m]=i,mu[i]=-1;
for(int j=1;j<=m&&prime[j]*i<=mx;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=mx;i++)
for(int j=i;j<=mx;j+=i)
f[j].sum+=i;
for(int i=1;i<=mx;i++)f[i].id=i;
}
void solve(int i)
{
int id=q[i].id,n=q[i].n,m=q[i].m;
for(int x=1,gx;x<=n;x=gx+1)
{
gx=min(n/(n/x),m/(m/x));
ans[id]+=(ask(gx)-ask(x-1))*(n/x)*(m/x);
}
}
int main()
{
qr(Q);
for(int i=1;i<=Q;i++)
{
qr(q[i].n),qr(q[i].m),qr(q[i].a),q[i].id=i;
if(q[i].n>q[i].m)swap(q[i].n,q[i].m);
mx=max(mx,q[i].n);
}
pre();
sort(q+1,q+Q+1,cmp1);
sort(f+1,f+mx+1,cmp2);
int now=0;
for(int i=1;i<=Q;i++)
{
while(now+1<=mx&&f[now+1].sum<=q[i].a)
{
now++;
for(int j=f[now].id;j<=mx;j+=f[now].id)
add(j,f[now].sum*mu[j/f[now].id]);
}
solve(i);
}
for(int i=1;i<=Q;i++)
qw(ans[i]&0x7fffffff),puts("");
return 0;
}