Time limit per test: 7.0 seconds
Time limit all tests: 7.0 seconds
Memory limit: 512 megabytes
Problem Description
在计算机和软件专业的联谊会上,计算机和软件的同学相间着排成一列。现在要计算相邻两个同学的友谊度。
友谊度 friend(a,b)是这么计算的:令 a, b两个整数分别是两个同学的属性,两个同学的友谊度取决于a,b第k大的公约数。如果不存在,就说明这两个同学之间完全没有友谊,友谊度为 −1。
Input
第一行是数据组数 T(1≤T≤60)。
对于每组数据:
第一行:首先是学生的数量n(1≤n≤10^5),约定的常数k(1≤k≤10^6)。第二行:n个整数,依次表示这些学生的属性值:m1,m2,…,mn(1≤mi≤10^6)。
Output
对于每组数据输出一行,以 Case x: 开头(x 表示数据编号,从1开始),后面是n−1个整数,分别是friend(m1,m2),friend(m2,m3),…,friend(mn−1,mn),整数和整数之间用空格隔开。
Examples
Input
2
3 1
4 6 12
6 2
13 12 12 24 36 30
Output
Case 1: 2 6
Case 2: -1 6 6 6 3
题解
可以考虑预处理出1到10^6中所有的数的所有因数。给每个数开个vector然后用类似筛法的方法,从小到大枚举,然后给所有这个数的倍数的vector加上这个数,结果我们就可以在因数总个数的线性时间内获得所有因数。如果你有统计过的话,是 10^7多一点。然后我们对每两个数求出 gcd,由于第 k大的 gcd 一定是 gcd 的因数,所以我们只要求 gcd 第 k小的因数然后除以它就可以了。如果不存在就是 −1。
此题还可以通过离线处理加速(因为可能取到的 k值是有限的),通过欧拉筛加速。但对于本题来说时限够宽以至于不做优化也能 AC。
代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
const int maxn = 1e6 + 10;
using namespace std;
int pr[maxn], num;
int a[maxn];
vector<int> G[maxn];
void init() {
for(int n = 1; n <= 1e6 ; n++) {
for(int i = 1; i *i <= n; i++) {
if(n % i) continue;
G[n].push_back(i);
if(n / i != i) G[n].push_back(n / i);
}
sort(G[n].begin(), G[n].end());
}
}
int divv(int n, int k) {
num = G[n].size();
if(k > G[n].size()) return -1;
return G[n][num - k];
}
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int main() {
int T, k, n;
init();
scanf("%d", &T);
for(int cse=1;cse<=T;cse++){
scanf("%d %d", &n, &k);
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
printf("Case %d:", cse);
for(int i = 1; i < n; i++) {
int g = gcd(a[i], a[i - 1]);
printf(" %d", divv(g, k));
}
printf("\n");
}
return 0;
}