题目:http://acm.nenu.edu.cn/regional-2015/files/2015/10/problemset_20151015.pdf
题意:
令
f(m)
表示满足
0≤a,b<m
且
m∤ab
的二元组
(a,b)
的个数。
令
g(n)=∑m|nf(m)
,询问
T
次某个
T≤20000,n≤109
。
题解:
(64位无符号整型变量的运算可以看做是在模
264
意义下的运算)
看到
g(n)
的形式很容易想到一个事实,如果
f(m)
是积性函数,即”对于互质的
a
和
令
n=pk11⋅pk22⋯pktt
,那么
g(n)=∑m|nf(m)=(f(1)+f(p1)+f(p21)+⋯+f(pk11))⋅(f(1)+f(p2)+f(p22)+⋯+f(pk22))⋯(f(1)+f(pt)+f(p2t)+⋯+f(pktt))=∏i=1t∑j=0kif(pji)
上面式子可以这样理解,对于每个 n 的因子
这样可以将 O(n−−√) 枚举因子的过程转化为 O(logn) 枚举质因子的过程。
然而这个题里的 f(m) 并不积性,原因很容易想到,因为它的定义应该是一个积性函数的反面,那么我们来看看这个反面。
定义 h(m) 表示满足 0≤a,b<m 且 m|ab 的二元组 (a,b) 的个数,那么显然就有 f(m)=m2−h(m) ,其中 m2 显然是一个积性函数,而考虑计算 h(m) 的时候,不难发现 a 和
先考虑 n 的所有因子
再来考虑 h(m) ,显然 a 和
考虑 m=pk 的情况,令 a=pta⋅ra,b=ptb⋅rb ,则 ra≤pk−ta且(ra,p)=1 , rb≤pk−tb且(rb,p)=1 。实际上,如果固定了 ta 和 tb , (a,b) 的个数是可以直接算出来的,即 ϕ(pk−ta)⋅ϕ(pk−tb) 。
现在所求即
h(m)=h(pk)=∑ta=0k∑tb=0k[ta+tb≥k]⋅ϕ(pk−ta)⋅ϕ(pk−tb)=∑ta=0k∑tb=0k[ta+tb≤k]⋅ϕ(pta)⋅ϕ(ptb)=∑i=0k∑j=0iϕ(pj)⋅ϕ(pk−j)=1+∑i=1k(i+1)pi−2ipi−1+(i−1)pi−2=(k+1)pk−kpk−1
更进一步地,有 ∑ki=0h(pi)=(k+1)pk 。
于是可以预处理出 O(n−−√) 以内的质数,单次 O(logn) 计算答案。
代码:
#include <cstdio>
typedef unsigned long long ULL;
const int maxn = 32000;
int tot, prime[maxn], t, n;
bool vis[maxn];
ULL ans1, ans2;
int main()
{
for(int i = 2; i < maxn; ++i)
{
if(!vis[i])
prime[tot++] = i;
for(int j = 0, o; j < tot && (o = i * prime[j]) < maxn; ++j)
{
vis[o] = 1;
if(i % prime[j] == 0)
break;
}
}
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
ans1 = ans2 = 1;
for(int i = 0; i < tot && prime[i] * prime[i] <= n; ++i)
if(n % prime[i] == 0)
{
int cnt = 0, tmp = 1;
ULL sum = 1;
for( ; n % prime[i] == 0; n /= prime[i], ++cnt);
for(int j = 1; j <= cnt; ++j)
{
tmp *= prime[i];
sum += (ULL)tmp * tmp;
}
ans1 *= sum;
ans2 *= tmp * (cnt + 1ULL);
}
if(n > 1)
{
ans1 *= (ULL)n * n + 1;
ans2 *= n * 2ULL;
}
printf("%llu\n", ans1 - ans2);
}
return 0;
}
然而会做这道题也不能拿金。