C. Border(exgcd/裴蜀定理)

https://codeforces.com/problemset/problem/1010/C

题意翻译

NatashaNatasha 抵达了火星.

火星上的钞票面额有nn种,第ii种的价值是a_iai​。NatashaNatasha 每个面额的钞票都有无数张。

火星人有kk个手指,所以他们使用kk进制。此外,火星人认为数字dd(在kk进制中)是神圣的。因此,如果凑出来的钱中在kk进制中最后一位数字是dd,火星人会很高兴。不幸的是,NatashaNatasha 还不知道dd是几。所以,他想知道他能凑出哪些数字。

输入输出样例

输入 #1复制

2 8
12 20

输出 #1复制

2
0 4 

输入 #2复制

3 10
10 20 30

输出 #2复制

1
0 

思路:首先看到k进制的最后一位数是每个数modk,然后这样暴力去统计的话还是无限个,所以一定不是这个方向。

正解:用到了exgcd的性质。

ax+by=c的不定方程有解的充要条件是c是gcd(a,b)的倍数。

所以多于多个数字而言,c是gcd(x1,x2,x3,x4...xn)的倍数。

既然是倍数而且题目说是无限个,所以只要求出了这个c,那么接下来后面的数只会是c的倍数。

比如c=gcd(x1,x2,x3),那么c肯定满足gcd(x1,x2),所以求出了c=gcd(x1,x2,x3....xn)后,然后枚举倍数0,1,2,3.....看c*i%k是不是出现过,出现过就停止,不然就继续枚举。

特别的当c=1时候,说明互质,也就是在k以内的1的倍数都可以取到。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
LL a[maxn],vis[maxn];
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,k;cin>>n>>k;
  for(LL i=1;i<=n;i++) cin>>a[i];
  LL res=0;
  for(LL i=1;i<=n;i++){
  	a[i]%=k;
  	res=__gcd(res,a[i]);
  }
  //debug(res);
  if(res==1){
  	cout<<k<<endl;
  	for(LL i=0;i<k;i++) cout<<i<<" ";
	cout<<endl;  
  }
  else if(res==0){
  	cout<<1<<endl;
  	cout<<0<<endl;
  }
  else{
 	LL ans=0;
 	for(LL i=0; ;i++){
 		if(vis[i*res%k]) break;
		else{
		   vis[i*res%k]++;ans++;
		} 	
	}
	cout<<ans<<endl;
	for(LL i=0;i<k;i++) if(vis[i]) cout<<i<<" ";
	cout<<endl;
  }
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108502505