题目大意
求 ∑ni=1∑mj=1[i,j] ,答案模 108+9 。多组询问。
T <= 10000
N, M<=10000000
思路
Crash的数字表格强化版。
我们进一步优化柿子
ans=∑d=1nd∑t=1⌊nd⌋t2μ(t)Sum(⌊ndt⌋,⌊mdt⌋)
枚举
dt
ans=∑D=1nSum(⌊nD⌋,⌊mD⌋)D∑i|Diμ(i)
令 G(D)=D∑i|Diμ(i) ,如果我们能求出 G(D) 的前缀和,那么就可以用 O(n√) 的时间处理每一个询问。
注意到积性函数的约数和也是积性函数。(为啥我没注意到呢)
于是 G(D) 也是积性函数,我们线性筛可求之。
对于
i%prime[j]==0
的情况,我们发现相对于
i
新增的约数
于是我们可以预处理出 G(D) 的前缀和了。本题在 O(Tn√) 的时间内即可解决。
PS:本题的模数真是鬼畜!若不是我无聊去数了一下,又要调一年!
代码
#include <bits/stdc++.h>
#define maxn 10000010
#define MOD 100000009
#define temp (i * prime[j])
using namespace std;
int n, m, T, cnt;
int prime[maxn], miu[maxn], g[maxn];
bool Vis[maxn];
void Da(){
miu[1] = g[1] = 1;
for(int i = 2; i < maxn; i++){
if(!Vis[i]){
prime[++cnt] = i;
miu[i] = -1;
g[i] = (i - 1LL * i * i % MOD + MOD) % MOD;
}
for(int j = 1; j <= cnt && temp < maxn; j++){
Vis[temp] = true;
if(i % prime[j] == 0){
miu[temp] = 0;
g[temp] = 1LL * g[i] * prime[j] % MOD;
break;
}
else{
miu[temp] = -miu[i];
g[temp] = 1LL * g[i] * g[prime[j]] % MOD;
}
}
}
for(int i = 2; i < maxn; i++) g[i] = (g[i] + g[i-1]) % MOD;
}
int Sum(int x, int y){
int temp1 = (1LL * x * (x + 1) >> 1) % MOD;
int temp2 = (1LL * y * (y + 1) >> 1) % MOD;
return 1LL * temp1 * temp2 % MOD;
}
int Solve(){
if(n > m) swap(n, m);
int ans = 0, last;
for(int i = 1; i <= n; i = last+1){
last = min(n/(n/i), m/(m/i));
ans = (ans + 1LL * (g[last] - g[i-1] + MOD) % MOD * Sum(n/i, m/i)) % MOD;
}
return ans;
}
int main(){
scanf("%d", &T);
Da();
while(T --){
scanf("%d%d", &n, &m);
printf("%d\n", Solve());
}
return 0;
}