传送门
md刚开始读错题了
本来不是很难的一道题被我搞的看起来不可能做出来?
首先看看数表里的数都是啥
实际上位置(i,j)上的数就是 f(gcd(i,j)) ,其中 f(i) 表示i的约数和
那么考虑一下怎么科学地求出来 f
约数和定理:
若 n=∏ipkii ,其中 pi 为n的质因子, ki 为质因子次数(正整数)
那么 n 的所有约数的和为 f(n)=∏i(∑j=0kipji)
可以发现当 (a,b)=1 时 f(ab)=f(a)f(b) ,那么 f 是一个积性函数
考虑线性筛,显然当 p 为质数时 f(p)=1+p ,当 (a,b)=1 时 f(ab)=f(a)f(b)
那么现在的问题是在原先的数上多加一个已有的质因子,也就是用 f(a) 和 p 推出 f(ap) ,其中 a mod p=0
同样还是要根据约数和公式。我们可以记录一个 g(i) ,表示i除去最小质因子剩下的数。
然后令 a=∏ipkii , p=p1 那么
如果不考虑a的限制的话,实际上就是求
考虑如何将a的限制插进去
实际上就是只有 f(d)≤a 的是有价值的
那么可以考虑离线之后将a排序,然后再将 f 排序,然后对于每一个a,将 f(d)≤a 的 f 都加入
至于怎么插入…我的方法是…暴力…
也就是对于一个d,枚举其n范围内的每个倍数, μ 和 f 都可以提前筛出来
类似于埃氏筛法的复杂度分析? O(nloglogn) ?不是很清楚大概比 O(n) 大一点
因为分块求的时候是 f 的前缀和,所以搞一个bit维护一下就行了
时间复杂度大约 O(n+Qlogn(n−−√+m−−√))
注意直接自然溢出就行了
#include
#include
#include
#include
#include
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]);
}
}