SDOI真的是什么毒瘤题都有qwq
这个题首先推式子的步骤我就不说了
最后长这个样子:(N<=M) (f(d)代表约数和函数)
∑T=1N⌊NT⌋⌊MT⌋∑d|Tf(d)∗μ(Td)
∑
T
=
1
N
⌊
N
T
⌋
⌊
M
T
⌋
∑
d
|
T
f
(
d
)
∗
μ
(
T
d
)
如果没有a的限制,这样就可以了
我们考虑如何处理那个限制
我们对询问离线,按照a排序
线性筛出来约数和以及莫比乌斯函数
我们按顺序插入每一个f(d)
每次枚举d的倍数计算对前缀和的贡献
树状数组维护前缀和
分块查询答案
要注意自然溢出,不然会TLE
O(maxn+Q(n‾√+m‾‾√)logmaxn) O ( m a x n + Q ( n + m ) l o g m a x n )
代码:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=1e5+5;
int cnt,prime[N],vis[N],f[N],mu[N],g[N];
inline void init(int n){
f[1]=1;mu[1]=1;g[1]=1;
for(int i=2;i<=n;++i){
if(!vis[i]){
prime[++cnt]=i;
mu[i]=-1;
g[i]=1;
f[i]=i+1;
}
for(int j=1;j<=cnt && i*prime[j]<=n;++j){
vis[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]];
}
}
}
}
const int Lim=1e5;
int t[N];
inline void add(int x,int v){
while(x<=Lim){
t[x]+=v;
x+=x&-x;
}
}
inline int query(int x){
int ans=0;
while(x){
ans+=t[x];
x-=x&-x;
}
return ans;
}
struct Query{
int n,m,lim,id;
Query(){}
inline bool operator < (const Query& b) const {return lim<b.lim;}
}q[N];
struct Insert{
int x,v;
Insert(){}
inline bool operator < (const Insert& b) const {return v<b.v;}
}I[N];
int mxval,num,Ans[N];
int main(){
init(1e5);
int T=read();
for(int i=1;i<=T;++i){
q[i].n=read();
q[i].m=read();
q[i].lim=read();
q[i].id=i;
mxval=max(mxval,q[i].lim);
}
sort(q+1,q+T+1);
for(int i=1;i<=Lim;++i){
if(f[i]<=mxval){
I[++num].x=i;
I[num].v=f[i];
}
}
sort(I+1,I+num+1);
int now=1;I[num+1].v=0x3f3f3f3f;
for(int s=1;s<=T;++s){
while(I[now].v<=q[s].lim){
int p=I[now].x;
for(int i=1;i*p<=Lim;++i){
add(i*p,I[now].v*mu[i]);
}
now++;
}
int n=q[s].n,m=q[s].m;
if(n>m)swap(n,m);
int ans=0;
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));
}
Ans[q[s].id]=ans;
}
for(int i=1;i<=T;++i){
Ans[i]&=2147483647;
printf("%d\n",Ans[i]);
}
return 0;
}