XDOJ1210 - 射击游戏

Description

zjy非常喜欢射击游戏,而且技术相当好,百发百中。@_@!

这次,他站在坐标系的(0,0)点。靶子位于格点(x,y)上,0 <= x <= n,0 <= y <= n,x,y均为整数。由于子弹不能穿过靶子( -_-! ) ,所以他不能打到被其他靶子遮住的靶子。上图显示了区域0 <= x <= 3, 0 <= y <= 3内的靶子(红点),以及zjy可以打得到的靶子。

给出n,计算区域0 <= x <= n, 0 <= y <= n内,zjy可以打到的靶子数目。

Input

多组数据,以-1结束。
每组数据一行,每行一个整数n(1 <= n <= 500000),表示区域的大小。

Output

输出一个整数,表示zjy可以打得到的靶子数目。

Sample Input

3
4
5
-1

Sample Output

9
13
21

Hint

结果不保证在32位之内,建议使用long long或I64d

解题思路:

 

简单数论题。设能打到的靶子为(x,y),则x,y必然互素。打表生成1…n内的欧拉函数,并求和sum=∑phi(i),1<=i<=n。(x,y)和(y,x)为两个不同的点,所以结果就是2*sum,考虑到(1,1)只有一个还要加上(1,0),(0,1)两个点,所以ans=2*sum+1 。

还要注意的是,要用生成素数的方法生成欧拉函数,否则会超时

 

#include<iostream>
#include<cmath>
using namespace std;
const int D = 500000;
int phi[D];

void init()
{
    for(int i=1;i<=D;++i)
        phi[i] = i;
    for(int i=2;i<=D;i+=2)
        phi[i] /= 2;
    for(int i=3;i<=D;i+=2)
        if(phi[i]==i)
        {
            for(int j=i;j<=D;j+=i)
                phi[j] = phi[j]/i*(i-1);
        }

}
int main()
{
    long long n;
    init();
    while(cin>>n)
    {
        if(n==-1)
            break;
        long long ans = 0;
        for(int i=0;i<n;++i)
            ans += phi[i+1];
        cout<<2*ans+1<<endl;
    }
    return 0;
}

 

最后欢迎大家访问我的个人网站: 1024s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值