以日记的形式进行更新每天在Codeforces中刷的题,大家可以随便看看,不会做过多的解释。
大致题意是在原有数列的基础上添加(也可以不加)几个新的数,使得新数列是一个Nice数列。数列满足所有数互不相同。Nice数列的定义是,从中任意取出两个数 x x x和 y y y,满足 ∣ x − y ∣ |x-y| ∣x−y∣在数列中存在。
Input
4
3
3 0 9
2
3 4
5
-7 3 13 -2 8
4
4 8 12 6
Output
yes
4
6 0 3 9
yEs
5
5 3 1 2 4
NO
Yes
6
8 12 6 2 4 10
稍加分析既可发现,只要数列中出现负数,则该数列一定不满足Nice,并且一个Nice数列必须满足一条性质:将所有的数从小到大排序后,该数列一定为一个等差数列,且首项为0或公差。
问题就在于如何去找到公差,并且加数到数列里面。
这里选择用gcd来寻找公差,查询数列中最小的数与每个数的最大公约数,找到的最小的gcd便是公差。
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a%b);
}
代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100000], b[100000];
int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a%b);
}
int main() {
int T, n;
scanf("%d", &T);
while(T-- > 0) {
bool fail = false, hasZero = false;
int minA = 10000, maxA = 0, gcdMin;
int num = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if(a[i] < 0) fail = true;
if(a[i] == 0) {
hasZero = true;
continue;
}
minA = min(minA, a[i]);
maxA = max(maxA, a[i]);
}
if(fail) {
printf("NO\n");
continue;
}else printf("YES\n");
gcdMin = minA;
for(int i = 1; i <= n; i++) {
if(!a[i]) continue;
gcdMin = min(gcdMin, gcd(gcdMin, a[i]));
}
for(int i = 0; i <= maxA; i += gcdMin) {
if(!i && !hasZero) continue;
b[++num] = i;
}
printf("%d\n", num);
for(int i = 1; i <= num; i++)
printf("%d ", b[i]);
printf("\n");
}
}