题意很明确。
题目不是很难,先讲讲正解,再分享一下我的一些想法(下面默认(n<m))
首先记(sigma(x))为(x)因数和
我们先不考虑a的影响,则题目所求的式子为
[sum^{n}_{x=1}{sum^{m}_{y=1} {sigma(gcd(i,j)) }}
]
显然我们枚举gcd
[sum^{n}_{d=1}sum^{n}_{x=1}{sum^{m}_{y=1} {sigma(d)[gcd(i,j)==d] }}
]
[sum^{n}_{d=1}sigma(d)sum^{lfloor frac{n} {d}
floor}_{x=1}{sum^{lfloor frac{m} {d}
floor}_{y=1} {[gcd(i,j)==1] }}
]
[sum^{n}_{d=1}sigma(d)sum^{lfloor frac{n} {d}
floor}_{x=1}{sum^{lfloor frac{m} {d}
floor}_{y=1} {sum_{t|gcd(i,j)}mu(t) }}
]
[sum^{n}_{d=1}sigma(d) {sum^{lfloor frac{n} {d}
floor}_{t=1}mu(t)sum^{lfloor frac{n} {td}
floor}_{x=1}{sum^{lfloor frac{m} {td}
floor}_{y=1}1}}
]
[sum^{n}_{d=1}sigma(d) {sum^{lfloor frac{n} {d}
floor}_{t=1}mu(t)lfloor frac{n} {td}
floorlfloor frac{m} {td}
floor}
]
设(s)=(t*d)
[sum^{n}_{s=1}lfloor frac{n} {s}
floorlfloor frac{m} {s}
floor {sum_{d|s}sigma(d)mu(frac{s}{d})}
]
前面的可以整除分块,那后面呢?
我们设(f(s)={sum_{d|s}sigma(d)mu(frac{s}{d})})
然后只要求出(f)的前缀和就(ok)了
别忘了还有一个a呢
欸,好像只要(sigma(gcd(i,j)))(leq)(a)就准保没事
(d=gcd(i,j))
也就是说(sigma(d))(leq)(a)才会给(f(s))做贡献
我们随便就可以求出(sigma(d))前(n)项的值 (O)((n)) (O(n*log n))随便跑
然后我们离线做,将输入的按(a)升序排列,(sigma(x))也升序排列
然后对于所有的(sigma(d)leq a)的我梦将他扩倍,换言之就是找所有的(d|s)中的(s)将(sigma(d)mu(frac{s}{d})) 加到(s)这个地方
单点插入,求前缀和,使用树状数组维护就行了
正解讲完了!!
谈谈我的一些其他想法
我最开始第一步都不是不是这么做的,显然死在半路上了
然后看自己第一步和最后一步都与大多题解都不一样时,我是自闭的
但其实是一样的。。
我的做法,也先不考虑(a)
[sum ^{n}_{i=1}sum ^{m}_{j=1}sum^{n}_{t=1}[t|i]\,[t|j] imes t
]
[sum ^{n}_{t=1}tsum ^{lfloor frac{n}{t}
floor}_{i=1}sum^{lfloor frac{m}{t}
floor}_{j=1}1
]
[sum ^{n}_{t=1}tlfloor frac{n}{t}
floorlfloor frac{m}{t}
floor
]
写到这看到题解我就懵了,因为得出结论
[t={sum_{d|s}sigma(d)mu(frac{s}{d})}
]
当时我以为我推错了 但他是对的!!
为啥呢?
首先大家都知道迪利克雷卷积
几个常见的结论
[varphi * 1 = id
]
[mu * id = varphi
]
[mu * 1 =varepsilon
]
[id *1 = sigma
]
同时他也有交换律,结合律
故(mu*id*1=varphi *1)
((mu*1)*id=varphi*1)
(varepsilon*id=id)
显然单位元乘(id)肯定等于(id),最后结论显然成立
所以我的和正解的式子是相同的
(没发现还是我太菜)
最后上代码了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+10,M=1e5,mod=1ll<<31ll;
ll mu[N],pr[N],p[N],tot,t[N],T,ans[N],n,m,a;
struct node{ll n,m,a,id;}h[N];
pair<ll,ll> s[N];
inline int cmp(node a,node c){return a.a<c.a;}
template<class T>void read(T &x){
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
}
inline void insert(ll x,ll v)
{
for(int i=x;i<=M;i+=(i)&(-i)) t[i]+=v;
}
inline ll query(ll x)
{
ll k=0;
for(int i=x;i>0;i-=(i)&(-i)) k+=t[i];
return k%mod;
}
int main()
{
mu[1]=1;
for(int i=2;i<=M;i++)
{
if(!pr[i]) p[++tot]=i,mu[i]=-1;
for(int j=1;p[j]*i<=M&&j<=tot;j++)
{
pr[i*p[j]]=1;
if(i%p[j]==0) break;
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=M;i++)
{
s[i].second=i;
for(register int d=1;d<=M/i;d++)
s[i*d].first+=d;
}
read(T);
for(register int i=1;i<=T;i++) read(h[i].n),read(h[i].m),read(h[i].a),h[i].id=i;
sort(s+1,s+1+M);
sort(h+1,h+1+T,cmp);
for(int i=1,j=1;i<=T;i++)
{
n=h[i].n,m=h[i].m,a=h[i].a;
while(s[j].first<=a&&j<=M)
{
for(ll d=1;d*s[j].second<=M;d++)
insert(d*s[j].second,s[j].first*mu[d]);
j++;
}
if(n>m) swap(n,m);
for(int l=1,r=1;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans[h[i].id]+=(n/l)*(m/l)*(query(r)-query(l-1));
}
ans[h[i].id]%=mod;
}
for(int i=1;i<=T;i++) printf("%lld
",ans[i]);
}