Description
Input
一个正整数T表示数据组数
接下来T行 每行两个正整数 表示N、M
Output
T行 每行一个整数 表示第i组数据的结果
Sample Input
1
4 5
Sample Output
122
HINT
T <= 10000
N, M<=10000000
分析:
关于式子的反演:LCM之和
(我实在不想再来一遍,不过听说舒老师有一种好方法,只能等ta传授了)
所以我们就有了这个式子:
但是我们这样就需要枚举两个量,即使是分块,时间复杂度还是无法承受
所以我们利用bzoj2820的奇技淫巧:
令 T=k*d
这样就改变了枚举顺序
如果我们能预处理出
我们就可以在sqrt(n)的时间内求出答案了
积性函数的乘积也是积性函数,可以线性筛
- n是质数:
- n不是质数:
- n的非平方质因子i:
- n的其他质因子i(即n=i*p且i|p):这样就会有一部分的mu值等于0,化简完得到:
- n的非平方质因子i:
tip
注意强制类型转换
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int N=1e7+2;
const ll p=100000009;
int n,m;
ll sum[N];
int sshu[N>>2],tot=0;
bool no[N];
void make()
{
sum[1]=1;
for (int i=2;i<N;i++)
{
if (!no[i])
{
sshu[++tot]=i;
sum[i]=(ll)((i-(ll)i*i%p)%p+p)%p; //ll
}
for (int j=1;j<=tot&&sshu[j]*i<N;j++)
{
no[sshu[j]*i]=1;
if (i%sshu[j]==0)
{
sum[i*sshu[j]]=(ll)(sum[i]%p*sshu[j]%p)%p; //ll
break;
}
sum[i*sshu[j]]=(ll)(sum[i]%p*sum[sshu[j]]%p)%p; //ll
}
}
for (int i=2;i<N;i++) sum[i]=(sum[i]%p+sum[i-1]%p)%p;
}
ll Sum(int n,int m)
{
return (ll)(n*(n+1)/2%p*m*(m+1)/2%p)%p;
}
int main()
{
int T;
make();
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
int last;
ll ans=0;
for (int i=1;i<=min(n,m);i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans=(ans%p+(Sum(n/i,m/i)%p*(sum[last]-sum[i-1])%p+p)%p)%p;
}
printf("%lld\n",ans);
}
return 0;
}