Dragonite神犇的题。。不知道省选现场怎么样。。
我们定义F(i)为i的约束和,题目要求的是
我们先忽略a这个限制,令
那么由莫比乌斯反演,可以得到g(i)=∑i∣d,d≤nμ(di)⌊nd⌋⌊md⌋
然后就有
Ans=∑i=1nF(i)g(i)
=∑i=1nF(i)∑i∣d,d≤nμ(di)⌊nd⌋⌊md⌋
=∑d=1n⌊nd⌋⌊md⌋∑i∣dF(i)μ(di)
我们令f(i)=∑i∣dF(i)μ(di),首先线性筛或者枚举每个数更新倍数来预处理出F(i),然后枚举每个数更新倍数,求出f(i)的前缀和,分块就好了。
考虑有了a的限制,我们发现只有
第一次写自然溢出,最后要and 231−1
#include<iostream>
#include<cstdio>
#include<algorithm>
#define lowbit(i) (i&(-i))
using namespace std;
int N;
struct query {int n,m,a,id;} q[40005];
bool flag[100005];
int prime[100005],min_factor_a[100005],min_factor_sum[100005],mobius[100005],tree[100005],ans[40005];
pair<int,int> F[100005];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline bool operator<(query a,query b)
{
return a.a<b.a;
}
inline void add(int x,int val)
{
for (int i=x;i<=N;i+=lowbit(i)) tree[i]+=val;
}
inline int query(int x)
{
int tmp=0;
for (int i=x;i;i-=lowbit(i)) tmp+=tree[i];
return tmp;
}
inline void prepare()
{
mobius[1]=F[1].first=F[1].second=1;
for (int i=2;i<=N;i++)
{
if (!flag[i])
{
prime[++prime[0]]=i;
mobius[i]=-1;
min_factor_a[i]=i;
min_factor_sum[i]=i+1;
F[i].first=i+1;
}
for (int j=1;j<=prime[0]&&i*prime[j]<=N;j++)
{
flag[i*prime[j]]=1;
if (i%prime[j]==0)
{
mobius[i*prime[j]]=0;
min_factor_a[prime[j]*i]=min_factor_a[i]*prime[j];
F[i*prime[j]].first=F[i].first/min_factor_sum[i]*(min_factor_sum[i]+min_factor_a[i*prime[j]]);
min_factor_sum[prime[j]*i]=min_factor_sum[i]+min_factor_a[i*prime[j]];
break;
}
mobius[i*prime[j]]=-mobius[i];
F[i*prime[j]].first=F[i].first*(prime[j]+1);
min_factor_a[i*prime[j]]=prime[j];
min_factor_sum[i*prime[j]]=(prime[j]+1);
}
}
for (int i=1;i<=N;i++) F[i].second=i;
}
inline void solve(int x)
{
for (int i=1,pos;i<=q[x].n;i=pos+1)
{
pos=min(q[x].n/(q[x].n/i),q[x].m/(q[x].m/i));
ans[q[x].id]+=(q[x].n/i)*(q[x].m/i)*(query(pos)-query(i-1));
}
}
int main()
{
int testcase=read();
for (int i=1;i<=testcase;i++)
{
q[i].n=read(),q[i].m=read(),q[i].a=read(),q[i].id=i;
if (q[i].n>q[i].m) swap(q[i].n,q[i].m);
N=max(N,q[i].n);
}
prepare();
sort(q+1,q+testcase+1);
sort(F+1,F+N+1);
int now=0;
for (int i=1;i<=testcase;i++)
{
while (now<N&&F[now+1].first<=q[i].a)
for (int j=F[++now].second;j<=N;j+=F[now].second)
add(j,F[now].first*mobius[j/F[now].second]);
solve(i);
}
for (int i=1;i<=testcase;i++)
printf("%d\n",ans[i]&0x7fffffff);
return 0;
}