poj2773 Happy 2006(用gcd函数进行的推导)

这个题目本来是想学一下容斥原理  网上发现有人用二分答案和容斥原理做的。。。后来又发现了更简单的解法 直接用gcd函数进行推导。。


题意就是给出m 和k m最大100w k最大 1亿

现在要求从1 开始 第k个 与m互素的数。

我们看gcd函数

gcd(a,b)=gcd(a%b,b)=gcd(a+b,b);

因为 a%b 和 (a+b)%b 是相等的。


这里能看出什么?

在 1-m 这个区间 和  m+1 到2m 这个区间

看 gcd(a,m) 和 gcd(a+m,m);  肯定是相当的 也就是说 以m为周期 互素的个数是一样的。


那么我们只要求出 1到m之间 与 m互素的数。

然后对于k 首先要k-- 因为 prim数组是从0到n的 k首先得--才能算出 就比如n=10,如果k是20 应该是一个周期 加上 prim的最后一个元素 也就是 19/10 +prim[9];

如果k是19 就是 18/10+prim[8];


之后找出有多少个周期。 就是 (k/n)*m  再在这个基础上 加上 prim[k%n] 就得到了。。注意用long long;


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxm=1000005;
const int maxk=100000005;

int prim[maxm];

int gcd(int a,int b)
{
    if(a==0) return b;
    else return gcd(b%a,a);
}

int main()
{
    int m,k;
    while(scanf("%d %d",&m,&k)!=EOF)
    {
        if(m==1)
        {
            printf("%d\n",k);
            continue;
        }
        int n=0;
        for(int i=1;i<m;++i)
        {
            if(gcd(i,m)==1)
            prim[n++]=i;
        }
        k--;
        printf("%lld\n",(LL)k/n * (LL)m +prim[k%n]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值