洛谷传送门
题目背景
付公主月考炸了,感到非常郁闷。
题目描述
为了排解心中的怒气,她造了大量的稻草人来发泄。每天付公主都会把一些稻草人摆成一个 R∗C R ∗ C 的矩形,矩形的每个方格上都有一个稻草人。然后她站在这个矩形的左上角,向矩形的右下角射箭。付公主的箭术过人,她能穿透任意多的稻草人。弓箭经过的方格上的稻草人难逃厄运,报废掉了。看着被毁坏的稻草人,付公主开心了一些。
但是制造稻草人需要大量的金钱,所以付公主不希望坏掉太多的稻草人,所以她每天都选择毁坏掉 N N 个稻草人。付公主还是个喜新厌旧的人,她希望每天能看到一种不同的稻草人摆放矩形。矩形是可以旋转的,即 和 C∗R C ∗ R 等价。她毫不费力地算出了摆放方案数,于是她决定刁难你一下。不甘示弱的你决定写个程序计算这个数来提交付公主的答卷。
输入输出格式
输入格式:
输入只有一行且只有一个数 N N ( ),代表每次被毁坏的稻草人数量。
输出格式:
一个整数表示总方案数。
输入输出样例
输入样例#1:
4
输出样例#1:
4
说明
样例解释:
对于 40%的数据, 1≤N≤10000 1 ≤ N ≤ 10000
对于 100%的数据, 1≤N≤1000000 1 ≤ N ≤ 1000000
解题分析
首先我们通过样例就可以发现一个显然的结论:当矩形为 N×M N × M 且 gcd(N,M)=1 g c d ( N , M ) = 1 时, 因为没有经过任何一个顶点, 所有格子都是穿过的, 且穿过了 N+M−1 N + M − 1 个格子。
然后我们就可以得到这样的式子:
然后 gcd(i,d+1−i)=gcd(i,d+1) g c d ( i , d + 1 − i ) = g c d ( i , d + 1 ) ,所以我们要求的是
O(N) O ( N ) 完美解决…
因为要去重, 而 N×N N × N 的矩形只算了一次, 所以最后的答案 =Ans+12 = A n s + 1 2
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 1000050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
}
int phi[MX], pri[MX];
int pcnt, n;
long long ans;
bool npr[MX];
void getphi()
{
R int i, j, tar, bd = n + 1;
for (i = 2; i <= bd; ++i)
{
if(!npr[i]) pri[++pcnt] = i, phi[i] = i - 1;
if(!(n % (i - 1))) ans += phi[i];
for (j = 1; j <= pcnt; ++j)
{
tar = pri[j] * i;
if(tar > bd) break; npr[tar] = true;
if(!(i % pri[j])) {phi[i * pri[j]] = pri[j] * phi[i]; break;}
else phi[i * pri[j]] = phi[i] * phi[pri[j]];
}
}
}
int main(void)
{
scanf("%d", &n);
getphi();
printf("%lld", (ans + 1) / 2);
}