Codeforces | CF1010C 【Border】
这道题大致题意是给定\(n\)个十进制整数和一个进制数\(k\),可以用无数多个给定的十进制整数,问这些十进制整数的和在模k意义下有多少种不同的结果(\(k\)进制下整数的最后一位就是这个数模\(k\)的余数)。
这明显是个数学题(但是不会做又有什么办法[逃]),既然是求模k意义下的可能结果,我们可以让所有数对k取模,这样可以得到末位数字。但是对于蒟蒻来说这有什么用呢(反正本蒟蒻取模之后也还是看不出来)。其实这道题并不是要取模,也不是要用进制,而是在十进制下求最大公约数(下面详细解释)。
众所周知有一道(毒瘤)题叫做小凯的疑惑,这道题的结论是对于互质的两个数\(a\)和\(b\),所有大于\(a \times b-a-b\)的数都可以用若干个\(a,b\)相加得到(别问我为什么看见这题想到了这个结论)\(\color{#FFF}{因为它太毒瘤啦qwq}\)。
看到这里蒟蒻一定会问,为什么这道题会和最大公约数有关呢?因为\(exgcd\)告诉我们二元一次方程\(ax+by=c\)在\(c\neq 0\ \ (mod \ \ gcd(x,y))\)时无整数解,这个非常简单,因为\(x=y= 0\ \ (mod \ \ gcd(x,y))\),所以\(c=0 \times a+0 \times b=0(mod\ \ gcd(x,y))\),那么设给定的\(n\)个数的最大公约数\(gcd({a_1},{a_2}, \cdots,{a_n} )=g\),则用给定的\(n\)个数的任意和都是\(g\)的倍数。既然所有\(g\)的倍数都可以构造,那么在模\(k\)意义下有多少个不同的数呢?此时就有一个二元一次方程\(ag=bk+r(0 \leq r <k)\),答案个数也即\(r\)的可能取值个数,变形可得\(ag-bk=r\),由\(exgcd\)得,当且仅当\(r = 0(mod\ gcd(g,k))\)时,方程有整数解。至此我们可以得到,对于任意的\(ans \in [0,k)\)满足\(ans \equiv 0 (mod\ gcd({a_1},{a_2},\cdots ,{a_n},k))\)都可以由若干个\({a_1},{a_2},\cdots,{a_n}\)相加得到(在模\(k\)意义下)。
以上是本题的思路叙述,下面放上\(AC\)代码\(\downarrow \downarrow \downarrow\)
#include<cstdio>//CF1010C
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cmath>
#include<algorithm>
#define N 100010
using namespace std;
int n,k,a[N],gg,ans;
int gcd(int a,int b){
if(b==0){
return a;
}
return gcd(b,a%b);
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
gg=a[1];
for(int i=2;i<=n;i++){
if(gg==1){
break;
}
if(a[i]>gg){
gg=gcd(a[i],gg);
}
else{
gg=gcd(gg,a[i]);
}
}
if(gg>k){
gg=gcd(gg,k);
}
else{
gg=gcd(k,gg);
}
ans=k/gg;
printf("%d\n",ans);
for(int i=0;i<ans;i++){
printf("%d ",i*gg);
}
return 0;
}
\(p.s.\)有一点小的细节,就是在\(gcd\)已经等于$ 1 $的时候跳出循环,这样能跑的更快一点(其实也快不到哪里去...本来跑的就不慢[逃])