题目链接:https://codeforc.es/contest/1011/problem/E

题目大意:有n种纸币,每种纸币有a[i]的面额,所有纸币无限,问所有可能的搭配转成k进制数后的最后一位有几种情况并输出

题目思路:转成k进制数后的最后一位即结果%k,由裴蜀定理a1*x1 + a2*x2 +...+ an * xn = c 有整数解,必有gcd(a1, a2,...,an) | c,那么我们只需要求出gcd,然后让gcd*0~k-1(代码里图打得方便多乘了k,效果是跟0一样可以忽略),就能得到所有可能情况,然后用set去重即可


对比c牛客的一道题

cf这个题需要将%k以内的所有解输出。。而牛客这个题是需要将能得到解的方案数输出。。题目类似,但是求得东西不太一样。。

因此cf是求得gcd,然后枚举gcd得倍数。牛客题则就dp了。

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MAXN = 1e5+5;
const ll MOD = 1e9+7;
ll n,k,a[MAXN];
set<ll>s;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
int main()
{
while(~scanf("%I64d%I64d",&n,&k)){
ll c=0;
rep(i,1,n){
scanf("%I64d",&a[i]);
c=gcd(a[i],c);
}
s.clear();
rep(i,0,k){
s.insert(c*i%k);
}
cout<<s.size()<<endl;
for(set<ll>::iterator iter=s.begin();iter!=s.end();iter++){
cout<<*iter<<" ";
}cout<<endl;
}
return 0;
}