LightOJ-1098 A New Function (数论、思维)
题目链接
其实是道简单题,但是感觉这里思维挺有意思的所以写个题解
题目大意:求出\(CSOD(n)=\sum_{i=1}^nSOD(i)\) 其中\(SOD(i)\)代表\(i\)的所有非1和它本身的约数和
首先确定约数\(x\)范围是从\(2\sim n/2\),然后对于每个约数\(x\)来说,从\(1\sim n\)的,以\(x\)作为因子的数有\([n/x]\)个,也就是\(x,2x,3x,4x...px(px\le n)\),除去第一个\(\textbf{x}\)(由于要求为约数和,不能包括自身)这里的和就是\(([n/x]-1)*x\),这里就有了一种复杂度为\(O(n)\)的朴素做法,显然会无情TLE
于是可以发现,对于每个约数\(x\)来说,\(2x,3x,4x...px(px\le n)\)中所对应的\(2,3,4...p\) 恰巧也是我们所需要的约数。其次\(\sqrt{n}\)是\(n\)以内最大所需约数(其余约数均可以用\(n/i\)表示),因此可以将答案表示为\(([n/x]-1)*x+\underline{(k+1)+(k+2)+...+p}\),后半部分显然直接等差数列求和,这样复杂度就降为\(O(\sqrt{n})\)
注意:由于 \(2\sim \sqrt{n}\)的约数都被遍历过,因此要在等差数列中删去
代码如下:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
int main()
{
int T, n;
scanf("%d", &T);
for (int cas = 1; cas <= T; ++cas)
{
LL result = 0;
scanf("%d", &n);
int end = sqrt(n);
for (int i = 2; i <= end; ++i)
{
LL cnt = n / i - 1;
result += cnt * i;
++cnt;
if (cnt > end)
result += ((LL)end + 1 + cnt) * (cnt - end) / 2;
}
printf("Case %d: %lld\n", cas, result);
}
}
努力变成更好的自己吧!

浙公网安备 33010602011771号