正文
X星球的某个大奖赛设了 M 级奖励。
每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。
比如:16,24,36,54,其等比值为:3/2。
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入格式
第一行为数字 N ,表示接下的一行包含 N 个正整数。
第二行 N 个正整数 Xi,用空格分开,每个整数表示调查到的某人的奖金数额。
输出格式
一个形如 A/B 的分数,要求 A、B 互质,表示可能的最大比例系数。
数据范围
0 < N < 100
0 < Xi < 10^12
数据保证一定有解。
输入样例1:
输出样例1:
输入样例2:
输出样例2:
输入样例3:
输出样例3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include<bits/stdc++.h> using namespace std; const int N = 110; typedef long long LL; int n; LL x[N],a[N],b[N]; LL gcd(LL a,LL b) { return !b ? a : gcd(b,a % b); }
LL gcd_sub(LL a,LL b) { if(a < b) swap(a,b); if(b == 1) return a; else return gcd_sub(b,a / b); } int main() { cin >> n; for(int i = 0;i < n;i++) cin >> x[i]; sort(x,x + n); int cnt = 0; for(int i = 1;i < n;i++) { if(x[i] != x[i - 1]) { LL d = gcd(x[i],x[0]); a[cnt] = x[i] / d; b[cnt] = x[0] / d; cnt++; } } LL up = a[0],down = b[0]; for(int i = 1;i < cnt;i++) { up = gcd_sub(up,a[i]); down = gcd_sub(down,b[i]); } cout << up << '/' << down << endl; return 0; }
|
注意:更相减损术
是另一种求最大公约数
的方法,时间上慢于gcd,大概是O(n)
的复杂度,但它适用于所有情况求最大公约数。涉及到约分
的gcd问题,可以考虑用它。
1 2 3 4 5 6 7 8
| LL gcd_sub(LL a,LL b) { if(a < b) swap(a,b); if(b == 1) return a; else return gcd_sub(b,a / b); }
|
该题简单分析后,可以转化为求几个分数的最大公约数问题
。问题在于,如何求分数的最大公约数呢?这里需要用到更相减损术。
正文
糖果店的老板一共有 M 种口味的糖果出售。
为了方便描述,我们将 M 种口味编号 1∼M。
小明希望能品尝到所有口味的糖果。
遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。
输入格式
第一行包含三个整数 N,M,K。
接下来 N 行每行 K 个整数 T1,T2,⋅⋅⋅,TK,代表一包糖果的口味。
输出格式
一个整数表示答案。
如果小明无法品尝所有口味,输出 −1。
数据范围
1 ≤ N ≤ 100,
1 ≤ M,K≤ 20,
1 ≤ Ti ≤ M
输入样例:
1 2 3 4 5 6 7
| 6 5 3 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2
|
输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include<bits/stdc++.h> using namespace std; const int N = 110,M = 1 << 20;
vector<int> col[N]; int n,m,k;
int logs2[M]; int lowbit(int x) { return x & -x; }
int h(int state) { int res = 0; for(int i = (1 << m) - 1 - state;i;i -= lowbit(i)) { res++; int c = logs2[lowbit(i)]; for(int j = 0;j < col[c].size();j++) i &= ~col[c][j]; } return res++; }
bool dfs(int depth,int state) { if(!depth || h(state) > depth) return state == (1 << m) - 1; int t = -1; for(int i = (1 << m) - 1 - state;i;i -= lowbit(i)) { int c = logs2[lowbit(i)]; if(t == -1 || col[c].size() < col[t].size()) t = c; } for(int i = 0;i < col[t].size();i++) { if(dfs(depth - 1,state | col[t][i])) return true; } return false; } int main() { cin >> n >> m >> k; for(int i = 0;i < m;i++) logs2[1 << i] = i; for(int i = 0;i < n;i++) { int state = 0; for(int j = 0;j < k;j++) { int c; cin >> c; state |= 1 << c - 1; } for(int j = 0;j < m;j++) { if(state >> j & 1) col[j].push_back(state); } } for(int i = 0;i < m;i++) { sort(col[i].begin(),col[i].end()); col[i].erase(unique(col[i].begin(),col[i].end()),col[i].end()); } int depth = 0; while(depth <= m && !dfs(depth,0)) depth++; if(depth > m) depth = -1; cout << depth << endl;
return 0; }
|
这题是一道较为复杂的暴搜,也是一种经典的完全覆盖问题
。完全覆盖问题的最优解法应该是Dancing Link
,有兴趣可以看下这篇帖子的讲解。写DFS应该先想搜索顺序,这里我们按照每种糖果来选糖袋
,可以保证不漏方案。直接DFS会超时,需要进行一些优化。首先,在顺序上,我们可以先选拥有糖袋较少的糖果
。同时采用迭代加深的方式进行DFS,也叫IDA*
,也是一种启发式搜索,所以我们还需要一个估价函数
,它用来预测当前选取状态之后最少还需要多少糖袋。对于每次选取的状态,我们还可以通过二进制
表示,这样可以加快枚举效率。