题目描述
题解
md刚开始读错题了
本来不是很难的一道题被我搞的看起来不可能做出来?
首先看看数表里的数都是啥
实际上位置(i,j)上的数就是
f(gcd(i,j))
,其中
f(i)
表示i的约数和
那么考虑一下怎么科学地求出来
f
约数和定理:
若
那么
n
的所有约数的和为
可以发现当
(a,b)=1
时
f(ab)=f(a)f(b)
,那么
f
是一个积性函数
考虑线性筛,显然当
那么现在的问题是在原先的数上多加一个已有的质因子,也就是用
f(a)
和
p
推出
同样还是要根据约数和公式。我们可以记录一个
g(i)
,表示i除去最小质因子剩下的数。
然后令
a=∏ipkii
,
p=p1
那么
观察这两个式子,可以得出: f(ap)=f(a)∗p+f(g(a))
这样我们就可以在 O(n) 的时间里得到 f 了
如果不考虑a的限制的话,实际上就是求
然后可以画一波柿子
然后利用反演公式 [n=1]=∑d|nμ(d)
然后令 T=dt ,现在 d 是
发现 μ 和 f 都是积性函数所以再搞一波线性筛就能求出卷积来了?
那你没发现没法满足a的性质了嘛?
考虑如何将a的限制插进去
实际上就是只有
那么可以考虑离线之后将a排序,然后再将
f
排序,然后对于每一个a,将
至于怎么插入…我的方法是…暴力…
也就是对于一个d,枚举其n范围内的每个倍数,
类似于埃氏筛法的复杂度分析?
因为分块求的时候是
f
的前缀和,所以搞一个bit维护一下就行了
时间复杂度大约
注意直接自然溢出就行了
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 100000
#define LL long long
int T;
int p[N+3],prime[N+3],mu[N+3],g[N+3],f[N+3],C[N+3],ans[N+3];
struct Q{int n,m,a,id;}q[N+3];
struct D{int val,id;}d[N+3];
void get()
{
mu[1]=1;f[1]=1;g[1]=1;
for (int i=2;i<=N;++i)
{
if (!p[i])
{
prime[++prime[0]]=i;
mu[i]=-1;
g[i]=1;
f[i]=i+1;
}
for (int j=1;j<=prime[0]&&i*prime[j]<=N;++j)
{
p[i*prime[j]]=1;
if (i%prime[j]==0)
{
mu[i*prime[j]]=0;
g[i*prime[j]]=g[i];
f[i*prime[j]]=f[i]*prime[j]+f[g[i]];
break;
}
else
{
mu[i*prime[j]]=-mu[i];
g[i*prime[j]]=i;
f[i*prime[j]]=f[i]*f[prime[j]];
}
}
}
for (int i=1;i<=N;++i) d[i].val=f[i],d[i].id=i;
}
void add(int loc,int val)
{
for (int i=loc;i<=N;i+=i&-i)
C[i]+=val;
}
int query(int loc)
{
int ans=0;
for (int i=loc;i>=1;i-=i&-i)
ans+=C[i];
return ans;
}
int cmpq(Q x,Q y)
{
return x.a<y.a;
}
int cmpd(D x,D y)
{
return x.val<y.val;
}
int calc(int n,int m)
{
int ans=0;
if (n>m) swap(n,m);
for (int i=1,j=0;i<=n;i=j+1)
{
j=min(n/(n/i),m/(m/i));
ans+=(n/i)*(m/i)*(query(j)-query(i-1));
}
return ans;
}
int main()
{
get();
sort(d+1,d+N+1,cmpd);
scanf("%d",&T);
for (int i=1;i<=T;++i) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].id=i;
sort(q+1,q+T+1,cmpq);
int now=1;
while (d[now].val<0) ++now;
for (int i=1;i<=T;++i)
{
while (now<=N&&d[now].val<=q[i].a)
{
for (int j=1;j*d[now].id<=N;++j)
add(j*d[now].id,mu[j]*d[now].val);
++now;
}
ans[q[i].id]=calc(q[i].n,q[i].m);
}
for (int i=1;i<=T;++i)
{
ans[i]&=2147483647;
printf("%d\n",ans[i]);
}
}