2277 密码

2277 密码

有一个密码箱,0到n-1中的某些整数是它的密码。且满足:如果a和b都是它的密码,那么(a+b)%n也是它的密码(a,b可以相等,%表示整除取余数),某人试了k次密码,前k-1次都失败了,最后一次成功了,问,该密码箱最多有多少不同的密码
对于二元一次不定方程,形式为ax+by=c其中a,b,c是整数,a×b≠0,此方程有整数解的成分必要条件 是gcd(a,b)|c
这个问题有两个结论
1.如果x是密码,那么gcd(x,n)也是密码
2.如果x,y是密码,那么gcd(x,y)也是密码,根据这两个结论,就能轻松地解决这个题了
先来证明第一个结论
构造一个方程xk-nc=gcd(x,n)也就是把xk%n写成了不是取模的形式,x×k减掉其中n的倍数;这个方程一定有解,也就是存在一个k使得xk%n=gcd(x,n),而x是密码,(x+x)%n也是密码,所以kx%n也是密码,那么gcd(x,n)就是密码
接着来证明结论2
通过一系列的推论就能证明
所以

对于任意一个密码集合A,分析:
1.设A中所有数的GCD为x
2.得到x属于A
3.如果密码集合中有比x小的数y,则gcd(x,y)<x不符合规定,所以x是A中最小的数


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll ;
const int N = 250010 ;
ll n , k , a[N] , ans , cnt ;
bool check(int x)
{
	for(int i = 1 ;i <= cnt ;i ++)
	 if(a[i] % x == 0)
	  return false ;
	return true ; 
}
ll gcd(ll a , ll b)
{
	return b == 0 ? a : gcd(b , a % b) ;
}
int main()
{
	scanf("%lld%lld" , &n , &k) ;
	for(int i = 1 ;i <= k ;i ++)
	 {
	 	scanf("%lld" , &a[i]) ;
	 	a[i] = gcd(a[i] , n) ;
	 }
	 sort(a + 1 , a + k) ;
	 for(int 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 ;
		 }
		printf("%lld\n" , ans) ;
       	 
	return 0 ;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值