例1.1-2 Strongbox

问题描述:

有一个密码箱,0到n-1中的某些整数是他的密码。条件:如果a b都是他的密码,则(a+b)%n也是他的密码。

某人试了k次密码均失败了,最后一次成功了。

问该密码箱最多有多少种不同的密码?

分析:

推导可得以下两个推论:

1,如果x是密码,则GCD(x,n)也是密码;

2,如果x y 是密码,则GCD(x,y)也是密码。

设密码集合中所有元素的GCD为x,则x是集合中的最小值,且集合中所有数为x 2x 3x ......

约束条件:

1,x|GCD(a[k],n);

2,x不能整除a[i] , i=1,2...k-1

求解步骤:

主要思路:求出x,ans=n/x

step1:求出GCD(a[i],n) i=1,2...k-1 并排序去重;

step2:捎带求出GCD(a[k],n),但不参与排序与去重;

step3:枚举GCD(a[k],n)的所有因子,最先满足约束条件2的即为x,ans=n/x,输出即可。

代码:

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
LL a[250005];//测试密码
LL cnt;

bool check(LL x)//过滤掉a[i]的因子
{
    for(LL i=1;i<=cnt;i++)
    {
        if(a[i]%x==0)return false;
    }
    return true;
}

LL GCD(LL a,LL b)
{
    return b?GCD(b,a%b):a;
}

int main()
{
    LL n,k;
    cin>>n>>k;
    LL ans=n;
    for(LL i=1;i<=k;i++)
    {
        cin>>a[i];
        a[i]=GCD(a[i],n);
    }
    sort(a+1,a+k);//为前k-1个排序
    for(LL i=1;i<k;i++)//去重
    {
        if(a[i]!=a[i-1])a[++cnt]=a[i];
    }

    for(LL i=1;i<=sqrt(a[k]);i++)
    {
        if(a[k]%i==0)
        {
            if(check(i))
            {
                ans=n/i;
                break;
            }
            else if(check(a[k]/i))
                ans=n/a[k]*i;
        }
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdau20171989/article/details/81257602
1.1