[Luogu P4388] 付公主的矩形

洛谷传送门

题目背景

付公主月考炸了,感到非常郁闷。

题目描述

为了排解心中的怒气,她造了大量的稻草人来发泄。每天付公主都会把一些稻草人摆成一个 RC R ∗ C 的矩形,矩形的每个方格上都有一个稻草人。然后她站在这个矩形的左上角,向矩形的右下角射箭。付公主的箭术过人,她能穿透任意多的稻草人。弓箭经过的方格上的稻草人难逃厄运,报废掉了。看着被毁坏的稻草人,付公主开心了一些。

但是制造稻草人需要大量的金钱,所以付公主不希望坏掉太多的稻草人,所以她每天都选择毁坏掉 N N 个稻草人。付公主还是个喜新厌旧的人,她希望每天能看到一种不同的稻草人摆放矩形。矩形是可以旋转的,即 RC CR C ∗ R 等价。她毫不费力地算出了摆放方案数,于是她决定刁难你一下。不甘示弱的你决定写个程序计算这个数来提交付公主的答卷。

输入输出格式

输入格式:

输入只有一行且只有一个数 N N 1N1000000),代表每次被毁坏的稻草人数量。

输出格式:

一个整数表示总方案数。

输入输出样例

输入样例#1:
4
输出样例#1:
4

说明

样例解释: img

对于 40%的数据, 1N10000 1 ≤ N ≤ 10000

对于 100%的数据, 1N1000000 1 ≤ N ≤ 1000000

解题分析

首先我们通过样例就可以发现一个显然的结论:当矩形为 N×M N × M gcd(N,M)=1 g c d ( N , M ) = 1 时, 因为没有经过任何一个顶点, 所有格子都是穿过的, 且穿过了 N+M1 N + M − 1 个格子。

然后我们就可以得到这样的式子:

Ans=d|Ni=1d+1[gcd(i,d+1i)=1] A n s = ∑ d | N ∑ i = 1 d + 1 [ g c d ( i , d + 1 − i ) = 1 ]

然后 gcd(i,d+1i)=gcd(i,d+1) g c d ( i , d + 1 − i ) = g c d ( i , d + 1 ) ,所以我们要求的是
Ans=d|Nϕ(d+1) A n s = ∑ d | N ϕ ( 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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值