题目链接:http://codeforces.com/problemset/problem/414/A
题意: 接收用户输入两个整数 n, k 。输出一个包含 n 个整数的序列:从前往后每次消除两个数,并计算其最大公约数,直到整数序列中数的个数小于 2(1 个或者 0 个)。在消除的过程中计算这些最大公约数的和。如果等于 k , 则赢。否则输。输出任意一个能赢的整数序列。
思路:n 个整数能形成 n / 2 对数据,即有且仅有 n / 2 个 “最大公约数”。如果 n/2 > k 的话,最大公约数全是 1 都不能得到 k ,则输出 -1 ;如果 n/2 == k 的话, 则输出 k 个最大公约数为 1 的整数对;如果 n/2 < k 的话,则说明一定存在某些数对的最大公约数大于 1, 因为是任意一个,我们可以输出一个最大公约数为 l = k - n/2 + 1 的数对,即(l, l*p(p >= 1)),取最小的就是(l, 2*l),然后在输出 n/2 - 1 个最大公约数为1的数对。这里面有个特殊情况是 k = 0, n = 1 即不取数对,就赢了。最大公约数为1的数对可以直接用两个连续的数。观察数据的范围(1 ≤ n ≤ 105; 0 ≤ k ≤ 108;1 ≤ ai ≤ 109)可以知道,2*l+1 ~ 109 的个数一定大于n (max 105 ),故可以在生成第一对数后,直接从 2*l + 1 开始往后面写 n-2 个数即可。
代码:
#include <stdio.h>
int main(){
int n, k, x;
scanf("%d%d", &n, &k);
x = n / 2;
if(x == 0 && k == 0)
printf("1");
else if(x > k || x == 0)
printf("-1");
else {
int l = k - x + 1;
printf("%d %d", l, 2*l);
l = 2*l + 1;
n -= 2;
while(n--)
printf(" %d", l++);
}
return 0;
}
如果要从小的开始写的话,可以从 2~l-1 && l+1 ~ 2*l -1 && 2*l + 1 ~ 一直下去,成对进行输出,最后,如果n为奇数,则最后再输出一个 1 ,否则就不用管。相较上面的做法显麻烦。
代码:
#include <stdio.h>
int main(){
int n, k, x, i;
scanf("%d%d", &n, &k);
x = n / 2;
if(k == 0 && n < 2){
printf("1");
return 0;
}
if(k < x || x < 1){
printf("-1");
return 0;
}
if(k == x){
for(i = 0; i < n; i++)
printf("%d ", i+1);
return 0;
}
int l = k - (x - 1);
printf("%d %d", l, 2*l);
n = n - 2;
while(n > 1){
for(i = 2; n > 1&& i+1 < l; i+=2){
printf(" %d %d", i, i+1);
n -= 2;
}
for(i = l+1; n > 1 && i+1 < 2*l; i+= 2){
printf(" %d %d", i, i+1);
n -= 2;
}
for(i = 2*l + 1; n > 1; i += 2){
printf(" %d %d", i, i+1);
n -= 2;
}
}
if(n == 1)
printf(" 1");
return 0;
}