问题描述:
有一个密码箱,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;
}