多组询问,每次询问给出 N、M、a,求满足 的上式值。
不考虑 a 的限制,按照一般的反演套路
令
令 (反向枚举 )
定义函数 ,并且令 (狄利克雷卷积)
如果没有 a 限制的话,时间复杂度是
如果加上 a 限制的话,首先线性预处理 [如何线性预处理],将询问按照 a 的大小排序,然后每次将 的 更新到当前询问的 ,然后数论分块 时间求出每一次询问的值。时间复杂度
AC代码
#include <bits/stdc++.h>
#define ll long long //T了就换int 试试
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e5 + 5;//用板子前先改范围
//const ll mod = 2147483648;
bool check[MAXN];//值为 false 表示素数,值为 true 表示非素数
//int phi[MAXN];//欧拉函数表
int prime[MAXN];//连续素数表
int mu[MAXN + 10];//莫比乌斯函数
int tot;//素数的个数(从0开始
//ll sub[MAXN];
ll sd[MAXN], sp[MAXN];
void jzk()
{
//memset(check, false, sizeof(check));
//phi[1] = 1;
mu[1] = 1;
sd[1] = 1;
tot = 0;
for (int i = 2; i < MAXN; i++)
{
if (!check[i])
{
prime[tot++] = i;
//phi[i] = i - 1;
mu[i] = -1;
sd[i] = i + 1;
sp[i] = i + 1;
}
for (int j = 0; j < tot; j++)
{
if (i * prime[j] >= MAXN)
break;
check[i * prime[j]] = true;
if (i % prime[j] == 0)
{
//phi[i * prime[j]] = phi[i] * prime[j];
mu[i * prime[j]] = 0;
sp[i * prime[j]] = (sp[i] * prime[j] + 1);//% mod;
sd[i * prime[j]] = (sd[i] / sp[i] * sp[i * prime[j]]);//% mod;
break;
}
else
{
//phi[i * prime[j]] = phi[i] * (prime[j] - 1);
mu[i * prime[j]] = -mu[i];
sd[i * prime[j]] = (sd[i] * sd[prime[j]]);//% mod;
sp[i * prime[j]] = (1 + prime[j]);//% mod;
}
}
}
//for (int i = 1; i < MAXN; i++)
// mu[i] = (mu[i] + mod) % mod;
}
struct node
{
ll n;
ll m;
ll a;
int id;
}in[20005];
ll ans[20005];
ll c[MAXN];
int lowbit(int k)
{
return k & (-k);
}
void upd(int k, ll val)
{
while (k < MAXN)
{
c[k] = (c[k] + val);//% mod;
k += lowbit(k);
}
}
ll query(int k)
{
ll ans = 0;
while (k)
{
ans = (ans + c[k]);//% mod;
k -= lowbit(k);
}
return ans;
}
#define Pair pair<ll,int>
Pair tt[MAXN];
int cmp(node q, node w) {
return q.a < w.a;
}
int cmp1(Pair q, Pair w) {
return q.first < w.first;
}
int main()
{
jzk();
int T;
sc("%d", &T);
for (int i = 0; i < T; i++)
{
sc("%lld%lld%lld", &in[i].n, &in[i].m, &in[i].a);
in[i].id = i;
}
sort(in, in + T, cmp);
for (int i = 1; i < MAXN; i++)
{
tt[i].first = sd[i];
tt[i].second = i;
}
sort(tt + 1, tt + MAXN, cmp1);
int now = 1;
for (int i = 0; i < T; i++)
{
while (now <= 1e5 && tt[now].first <= in[i].a)
{
for (int i = tt[now].second, cnt = 1; i < MAXN; i += tt[now].second, cnt++)
upd(i, mu[cnt] * tt[now].first);//% mod);
now++;
}
ll res = 0, j;
ll n = in[i].n, m = in[i].m;
ll minn = min(n, m);
for (ll i = 1; i <= minn; i = j + 1)
{
j = min(n / (n / i), m / (m / i));
res = (res + (n / i) * (m / i) * (query(j) - query(i - 1)));
}
ans[in[i].id] = res;
}
for (int i = 0; i < T; i++)
pr("%lld\n", ans[i] & 2147483647);// + mod) % mod);
}
/*
5
4 4 1
4 4 2
4 4 3
4 4 4
4 4 5
*/