【JZOJ 1709】【SDOI2008】仪仗队

Description
 作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的生后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
  现在,C 君希望你告诉他队伍整齐时能看到的学生人数。
 这里写图片描述
Input

  共一个数N。

Output

  共一个数,即C 君应看到的学生人数。

Sample Input

4

Sample Output

9

Data Constraint

Hint

【数据规模和约定】
  对于30 %的数据,1 <= N <= 1000
  对于100 %的数据,1 <= N <= 40000

The Solution

首先这个矩阵是对称的,我们可以先只看一半。
仔细观察我们可以发现若(x,y)是可看见的点,那么他们满足gcd(x,y)=1.
即:如果可看见的点都是x/y的最简式的形式。

理由如下:

因为如果可以再化简,则说明其最简式一定被看过了。

所以

题目就转换成在1 ~N的范围内x,y互质的个数。

而我们是只看半的,所以左后结果要*2,而其中(1,1)是特别的,最后要剪掉。
而最后结果存在(0,1),(1,0)随意答案要加2.

所以最后可以这样表示.

Ans=2n1I=1ϕ(i)+1

求phi可以用线筛,也可以用普通方法。

把这道题当成线筛phi模板题了 。。。

CODE

线筛版:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cmath>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 40005

using namespace std;

typedef long long ll;

int Phi[N],Pre[N],ans = 0;
int Prime[N],tot = 0,n;
bool bz[N];

void PHI()
{
    Phi[1] = 1;
    fo(i,2,n)
    {
        if (!bz[i]) Phi[i] = i - 1,Prime[++ tot] = i;
        fo(j,1,tot)
        {
            int x = Prime[j];
            if (i * x > n) break;
            bz[i * x] = true;
            if (i % x == 0) 
            {
                Phi[i * x] = Phi[i] * x;
                break;
            }
            else Phi[i * x] = Phi[i] * Phi[x];
        } 
    }
}

int main()
{
    scanf("%d",&n);
    PHI();
    fo(i,1,n - 1) ans = ans + Phi[i];
    printf("%d\n",ans * 2 + 1);
}

普通phi

#include <cstdio>
#include <iostream>
#include <cmath>
#define fo(i,a,b) for (int i=a;i<=b;i++)

using namespace std;

typedef long long ll;

ll ans = 0;

ll PHI(int x)
{
    ll res = x;
    fo(i,2,(int)sqrt(x))
    {
        if (x % i == 0)
        {
            res = res * (ll)(i - 1) / i;
            while (x % i ==0) x /= i;
        }
    }
    if (x > 1) res = res * (ll)(x - 1) / x;
    return res;
}

int main()
{
    int n;
    scanf("%d", &n);
    fo(i,1,n-1) ans += PHI(i);
    printf("%lld\n",ans * 2 + 1);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值