745 Sum of Squares

Problem 745

对任意正数 , 是最大的能被 整除的完全平方数。

比如 。

定义 例如 。

求 ,结果模 。

非常大,遍历肯定是不现实的。

但是小于这个值的完全平方数只有 个,遍历几遍也足够快。如果知道了所有的完全平方数的根,那么其完全平方数及其整倍数 对应的 就得到了。直观地看,有很多 ,其 都是1。

我们只需要计算每个完全平方数的根 是多少个 的次数即可(即满足 的 的个数),因为计算 的时候可以用完全平方数乘以次数。

如果两个完全平方数的根 ,有关系 ,那么计算平方数及其整倍数的时候需要注意一下。,但是 也能整除 。所以我们需要从大的平方根向小的平方根遍历,对于后者 ,对应的 个数(即满足 的 的个数),需要减去 对应的 的个数。

首先定义几个常量

private static readonly long N = 100_000_000_000_000;
private static readonly int NSqrt = 10_000_000;
private static readonly int Mod = 1_000_000_007;
下面计算完全平方数的根对应的 的个数。从大往小计算,同时对于更小的数 ,需要把其整数倍对应的 的个数减去。
var counts = new long[NSqrt + 1];
for (long i = counts.Length - 1; i >= 2; i--)
{
    long count = N / (i * i);
    for (long j = i * 2; j < counts.Length; j += i)
    {
        count -= counts[j];
    }

    counts[i] = count;
}
还有一个问题没有讨论, 的个数。这个很简单,总数 减去上面统计的次数之和即可。
long sum = N;
for (int i = 2; i < counts.Length; i++)
{
    sum -= counts[i];
}
至此,sum 就是 的个数。现在加上完全平方数和对应次数的乘积。整个运算中,为了保持数很小(不超出 long 的范围),需要不停的取模。
sum %= Mod;

for (long i = 2; i < counts.Length; i++)
{
    sum += counts[i] * i * i;
    sum %= Mod;
}