煤球数目 T-1 (分值:3)
题目:煤球数目
有一堆煤球,堆成三角棱锥形。具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形), .... 如果一共有100层,共有多少个煤球? 请填表示煤球总数目的数字。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
1 * (1) 2 *** (3) 3 ****** (6) 4 ********** (10) 5 ..............(15) ————————————————————————————————————————————————————————————*
/**
* pre 定义上一层
* plus 定义增量差值 */
#include <iostream>
using namespace std;
int main(int argc, char const* argv[])
{
int pre = 1; //
int plus = 2; //
long sum = 1;
for (int k = 2; k <= 100; ++k)
{
sum += (pre + plus);
pre = pre + plus;//sum+=pre
plus++;
}
cout << sum << endl;
return 0;
}
//结果:171700
生日蜡烛 T-2 (分值:5)
某君从某年开始每年都举办一次生日party, 并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来,他一共吹熄了236根蜡烛。 请问,他从多少岁开始过生日party的? 请填写他开始过生日party的年龄数。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
#include <iostream>
using namespace std;
int main()
{
int begin_candle = 0;
while (true)
{
begin_candle++;
int sum = 0, age = begin_candle;
while (age <= 100)
{
sum += age;
age++;
if (sum == 236)
{
cout << "开始吹蜡烛年龄: " << begin_candle << endl;
cout << "现在年龄: " << age << endl;
return 0;
}
}
}
return 0;
}
凑算式 T-3 (分值:11)
题目:凑算式
B DEF A + --- + ------- = 10 C GHI
(如果显示有问题,可以参见【图1.jpg】) 这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。 比如:
6+8/3+952/714
就是一种解法,5+3/1+972/486
是另一种解法。 这个算式一共有多少种解法? 注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
#include <iostream>
#include <algorithm>
using namespace std;
int AL[] = { 1,2,3,4,5,6,7,8,9 };
int ans = 0;
void check_Ans() {//检查答案是否正确
int D_F = AL[3] * 100 + AL[4] * 10 + AL[5];
int G_I = AL[6] * 100 + AL[7] * 10 + AL[8];
int P_S = AL[1] * G_I + AL[2] * D_F; //通分后分子
int P_P = AL[2] * G_I; //通分后分母
//必须满足(B*GHI+C*DEF)%(C*GHI)能除尽 并且 满足公式要求
if (P_S % P_P == 0 && (AL[0] + P_S / P_P) == 10)
ans++;
}
int main()
{
//AL全排列后匹配答案
while (next_permutation(AL, AL + 9))
check_Ans();
cout << ans << endl;
return 0;
}
快速排序 T-4 (分值:9)
排序在各种场合经常被用到。 快速排序是十分常用的高效率的算法。 其思想是:先选一个“标尺”, 用它把整个队列过一遍筛子, 以保证:其左边的元素都不大于它,其右边的元素都不小于它。 这样,排序问题就被分割为两个子区间。 再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#include <stdio.h>
void swap(int a[], int i, int j)//交换
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int a[], int p, int r)
{
int i = p; //i指向大于x ——>找大
int j = r + 1; //j指向小于等于x ——>找小
int x = a[p];
while (1) {
while (i < r && a[++i] < x);
while (a[--j] > x);
if (i >= j) break;
swap(a, i, j);
}
/*代码填空处
swap(a,p,j) ; //
______________________; */
swap(a, p, j);
return j;
}
void quicksort(int a[], int p, int r)
{
if (p < r) {
int q = partition(a, p, r); //q为标尺
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);
}
}
int main()
{
int i;
int a[] = { 5,13,6,24,2,8,19,27,6,12,1,17 };
int N = 12;
quicksort(a, 0, N - 1); //排序
for (i = 0; i < N; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
抽签 T-5 (分值:13)
X星球要派出一个5人组成的观察团前往W星。 其中: A国最多可以派出4人。 B国最多可以派出2人。 C国最多可以派出2人。 ....
那么最终派往W星的观察团会有多少种国别的不同组合呢?
下面的程序解决了这个问题。 数组a[] 中既是每个国家可以派出的最多的名额。 程序执行结果为:
DEFFF CEFFF CDFFF CDEFF CCFFF CCEFF CCDFF CCDEF BEFFF BDFFF BDEFF BCFFF BCEFF BCDFF BCDEF .... (以下省略,总共101行)
//递归填空
#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024
/**
* k = 数组的下标
* m代表人数,初始为5
* b缓冲字符串
*/
int ans = 0;
void f(int a[], int k, int m, char b[])
{
int i, j;
if (k == N) {
b[M] = 0; //字符串结尾的标志
if (m == 0) { printf("%s\n", b); ans++; }
return;
}
//递归
for (i = 0; i <= a[k]; i++) { //试着将k国家,排除i人
for (j = 0; j < i; j++) b[M - m + j] = k + 'A'; //填充buf,有i人就填i个国家符号(k+'A')
/*代码填空处
f(a,k+1,m-i,b) ;
______________________; */
f(a, k + 1, m - i, b);
}
}
int main()
{
int a[N] = { 4,2,2,1,1,3 };
char b[BUF];
f(a, 0, M, b);
printf("%d\n", ans);
return 0;
}
方格填数 T-6 (分值:19) 没理解,再看看
如下的10个格子
+--+--+--+ | | | | +--+--+--+--+ | | | | | +--+--+--+--+ | | | | +--+--+--+(如果显示有问题,也可以参看【图1.jpg】) 填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻) 一共有多少种可能的填数方案?
请填写表示方案数目的整数。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int map[6][6];
int ans = 0;
int Abs(int i, int j)//判断 8个方向
{
if (abs(map[i - 1][j] - map[i][j]) == 1)
return 0;
if (abs(map[i + 1][j] - map[i][j]) == 1)
return 0;
if (abs(map[i][j + 1] - map[i][j]) == 1)
return 0;
if (abs(map[i][j - 1] - map[i][j]) == 1)
return 0;
if (abs(map[i - 1][j - 1] - map[i][j]) == 1)
return 0;
if (abs(map[i + 1][j - 1] - map[i][j]) == 1)
return 0;
if (abs(map[i - 1][j + 1] - map[i][j]) == 1)
return 0;
if (abs(map[i + 1][j + 1] - map[i][j]) == 1)
return 0;
return 1;
}
int f()//判断相邻的数是否连续
{
if (Abs(1, 3) && Abs(2, 1) && Abs(2, 2) && Abs(2, 3) && Abs(2, 4) && Abs(3, 2))
return 1;
return 0;
}
int main()
{
memset(map, -2, sizeof(map));
int a[] = { 0,1,2,3,4,5,6,7,8,9 };
do {
map[1][2] = a[0];
map[1][3] = a[1];
map[1][4] = a[2];
map[2][1] = a[3];
map[2][2] = a[4];
map[2][3] = a[5];
map[2][4] = a[6];
map[3][1] = a[7];
map[3][2] = a[8];
map[3][3] = a[9];
ans += f();
} while (next_permutation(a, a + 10));
cout << ans << endl;
return 0;
}
剪邮票 T-7 (分值:19)
如【图1.jpg】, 有12张连在一起的12生肖的邮票。 现在你要从中剪下5张来,要求必须是连着的。 (仅仅连接一个角不算相连)
+--+--+--+--+ | | | | | +--+--+--+--+ | | | | | +--+--+--+--+ | | | | | +--+--+--+--+比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。 请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
/*
1 2 3 4
5 6 7 8
9 10 11 12
思路1:每个格子作为起点,dfs连五张,去重->结果
思路2:暴力枚举,所有的五张组合,检查它们是不是一个连通块。 */
// 12/13 寒假作业 12/5 dfs
/*思路1: 生成的方法有太多的重复,效率低下
//此题和13年剪格子有相似之处,但是那个题的限制条件是格子数值之和为总和的一半,此题则限制只能是5个格子
//单纯的dfs无法解决T字型连通方案
//本题的解决办法是,找出任意5个格子,判断是否连通*/
#include <algorithm>
#include <iostream>
using namespace std;
int ans;
bool check(int arr[12]);
void dfs(int g[3][4], int i, int j);
int main(int argc, const char *argv[]) {
int per[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
do {
if (check(per))
ans++;
} while (next_permutation(per, per + 12));
cout << ans << endl;
return 0;
}
bool check(int arr[12]) {
int g[3][4];
memset(g, 0, sizeof(g));
//将相应位置标注为1
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
if (arr[i * 4 + j] == 1)g[i][j] = 1;
}
}
// 经典连通块计算
int cnt = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
if (g[i][j] == 1) {
dfs(g, i, j);
cnt++;
}
}
}
return cnt == 1;
}
void dfs(int g[3][4], int i, int j) {
g[i][j] = 0;
if (i + 1 <= 2 && g[i + 1][j] == 1) dfs(g, i + 1, j);
if (i - 1 >= 0 && g[i - 1][j] == 1) dfs(g, i - 1, j);
if (j + 1 <= 3 && g[i][j + 1] == 1) dfs(g, i, j + 1);
if (j - 1 >= 0 && g[i][j - 1] == 1) dfs(g, i, j - 1);
}
//思路2:跑不出来
#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
int a[]={0,0,0,0,0,0,0,1,1,1,1,1};//它的每个排列代表着12选5的一个方案
int ans;
void dfs(int g[3][4],int i , int j){
g[i][j]=0;
if(i-1>=0&&g[i-1][j]==1)dfs(g,i-1,j);
if(i+1<=2&&g[i+1][j]==1)dfs(g,i+1,j);
if(j-1>=0&&g[i][j-1]==1)dfs(g,i,j-1);
if(j+1<=3&&g[i][j+1]==1)dfs(g,i,j+1);
}
bool check(){
int g[3][4];
// 将某个排列映射到二维矩阵上
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
if(a[i*4+j]==1) g[i][j]=1;
else g[i][j]=0;
}
}
int cnt=0;//连通块的数目
// g上面就有5个格子被标记为1,现在才用dfs做连通性检查,要求只有一个连通块
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
if(g[i][j]==1){
dfs(g,i,j);
cnt++;
}
}
}
return cnt==1;
}
set<string> s1;
void a2s(string &s){
for (int i = 0; i < 12; ++i) {
s.insert(s.end(),a[i]+'0');
}
}
bool isExist(){
string a_str;
a2s(a_str);
if(s1.find(a_str)==s1.end()){
s1.insert(a_str);
return false;
} else
return true;
}
void f(int k){
if(k==12){
if(!isExist()&&check()){
ans++;
}
}
for (int i = k; i < 12; ++i) {
{int t=a[i];a[i]=a[k];a[k]=t;}
f(k+1);
{int t=a[i];a[i]=a[k];a[k]=t;}
}
}
int main(int argc, const char *argv[]) {
f(0);
printf("%d",ans);
//string _s;
//a2s(_s);
//cout<<_s<<endl;
return 0;
}
//思路3:
#include <algorithm>
#include <iostream>
using namespace std;
//它的每个排列代表着12选5的一个方案
int a[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
int ans;
void dfs(int g[3][4], int i, int j)
{
g[i][j] = 0;
if (i - 1 >= 0 && g[i - 1][j] == 1)dfs(g, i - 1, j);
if (i + 1 <= 2 && g[i + 1][j] == 1)dfs(g, i + 1, j);
if (j - 1 >= 0 && g[i][j - 1] == 1)dfs(g, i, j - 1);
if (j + 1 <= 3 && g[i][j + 1] == 1)dfs(g, i, j + 1);
}
bool check(int path[12])
{
int g[3][4];
// 将某个排列映射到二维矩阵上
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (path[i * 4 + j] == 1) g[i][j] = 1;
else g[i][j] = 0;
}
}
int cnt = 0;//连通块的数目
// g上面就有5个格子被标记为1,现在才用dfs做连通性检查,要求只有一个连通块
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (g[i][j] == 1)
{
dfs(g, i, j);
cnt++;
}
}
}
return cnt == 1;
}
bool vis[12];
void f(int k, int path[12])
{
if (k == 12) {
if (check(path))
{
ans++;
}
}
for (int i = 0; i < 12; ++i)
{
if (i>0&&a[i]==a[i-1]&&!vis[i-1])continue;//现在准备选取的元素和上一个元素相同,但是上一个元素还没被使用
if(!vis[i]){//没有被用过的元素可以抓入到path
vis[i]=true;//标记为已访问
path[k]=a[i];//将a[i]填入到path[k]中
f(k + 1, path);//递归
vis[i]=false;//回溯
}
}
}
int main(int argc, const char *argv[])
{
int path[12];
f(0, path);
printf("%d", ans);
return 0;
}
四平方和 T-8 (分值:21) 研究一下
题目:四平方和
四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多4个正整数的平方和。 如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2 7 = 1^2 + 1^2 + 1^2 + 2^2(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。 要求你对4个数排序:
0 <= a <= b <= c <= d并对所有的可能表示法按 a,b,c,d 为联合主键升序排列, 最后输出第一个表示法
程序输入为一个正整数N (N<5000000) 要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:0 0 1 2
再例如,输入:
12
则程序应该输出:0 2 2 2
再例如,输入:
773535
则程序应该输出:1 1 267 838
资源约定: 峰值内存消耗 < 256M CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似: “请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准, 不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
//枚举+优化
//优化:采用缓存来空间换时间
/*思路1:
枚举abcd
for(a) 0~a^2
for(b) 0~b^2
for(c) 0~c^2
for(d) 0~d^2
*/
#include<iostream>
#include<cstdio>
#include<map>
int N;
using namespace std;
map<int, int>cache;
int main()
{
scanf_s("%d", &N);
//
for (int c = 0; c * c <= N / 2; ++c)
for (int d = c; c * c + d * d <= N; ++d)
if (cache.find(c * c + d * d) == cache.end())
cache[c * c + d * d] = c;
//
for (int a = 0; a * a <= N / 4; ++a)
for (int b = a; a * a + b * b <= N / 2; ++b)
if (cache.find(N - a * a + b * b) != cache.end()) {
int c = cache[N - a * a + b * b];
int d = int(sqrt(N - a * a + b * b + c * c));
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}
return 0;
}
交换瓶子 T-9 (分值:23)
有N个瓶子,编号 1 ~ N,放在架子上。 比如有5个瓶子:
2 1 3 5 4
要求每次拿起2个瓶子,交换它们的位置。 经过若干次后,使得瓶子的序号为:1 2 3 4 5
对于这么简单的情况,显然,至少需要交换2次就可以复位。 如果瓶子更多呢?你可以通过编程来解决。 输入格式为两行: 第一行: 一个正整数N(N<10000), 表示瓶子的数目 第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。 输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。例如,输入:
5 3 1 2 5 4
程序应该输出:
3
再例如,输入:5 5 4 3 2 1
程序应该输出:
2
资源约定: 峰值内存消耗 < 256M CPU消耗 < 1000ms请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准, 不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。 提交时,注意选择所期望的编译器类型。
/*
3 2 1 5 4
[1] [2] [3] [4] [5] */
// 贪心
#include <iostream>
using namespace std;
int n;
int a[10001];
int ans;
int pos(int x)
{
for (int i = 1; i <= n; ++i)
{
if (a[i] == x)return i;
}
return -1;
}
void swap(int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
void printArr() {
for (int i = 1; i <= n; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
int main(int argc, const char* argv[])
{
// 处理输入
scanf_s("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf_s("%d", &a[i]);
}
//遍历i:1-N
for (int i = 1; i <= n; ++i)
{
//如果a[i]=i,已经到位
if (a[i] == i)continue;
//否则先找到i在a中的位置pos(i)和i位交换——swap(a,pos(i),i)
else
{
swap(pos(i), i);
ans++;
}
}
//printArr();
printf("%d\n", ans);
return 0;
}
最大比例 T-10 (分值:31)
题目:最大比例
X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。 并且,相邻的两个级别间的比例是个固定值。 也就是说:所有级别的奖金数构成了一个等比数列。比如: 16,24,36,54 其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。 请你据此推算可能的最大的等比值。
输入格式: 第一行为数字 N (0<N<100),表示接下的一行包含N个正整数 第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。 每个整数表示调查到的某人的奖金数额 要求输出: 一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数 测试数据保证了输入格式正确,并且最大比例是存在的。
例如,输入:
3 1250 200 32
程序应该输出:
25/4
再例如,输入:
4 3125 32 32 200
程序应该输出:
5/2
再例如,输入:
3 549755813888 524288 2
程序应该输出:
4/1
资源约定: 峰值内存消耗 < 256M CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似: “请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准, 不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
/*
等比数列:a0、a1、a2、a3、a4
等比数列的性质:
a3 p
—— ——> (———)^2
a0 q
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std ;
typedef long long LL ;
int N ;
LL data[100] ;
struct Ratio{
LL x,y ;
Ratio(LL _x,LL _y):x(_x),(_y)
{
LL _gcd = gcd(x,y) ;
x /= _gcd ;
y /= _gcd ;
}
LL gcd(LL a,LL b)
{
if(b==0) return a ;
return gcd(b,a%b) ;
}
} ;
//存储比值
vector<Ratio> ratios ;
int main()
{
//处理输入
scanf("%d",&n) ;
for (int i = 0; i < N; ++i) //扫描输入数据
{
scanf("%lld",&data[i]) ;
}
//排序
sort(data,data+N) ;
//两两比值,以分数形式存储,vector
for (int i = 0; i < N-1; ++i)
{
if(data[i+1]!=data[i])//去重
ratios.push_back(Ratio(data[i+1],data[]i)) ;
}
/*对第一个比值开1-..pow(极限为40)次方作为基数,
如果这个基数的分子、分母的k1
k2次方恰好是其他比值的分子分母的话,基数就是答案*/
for (int pow = 0; pow <= 40; ++pow)
{
Ratio ra0 = ratios[0] ;
LL x = ra0.x ;
LL y = ra0.y ;
LL fx = extract(x,pow) ; //对
LL fy = extract(y,pow) ; //
if(fx==-1 |\ fy ==-1) continue ; //开不出,continue
//能开,就要确认所有比值的分子是fx的整数次方,所有比值的分母是fy的整数次方
//计px=getPow(xx,fx),py=getPow(yy,fy),要求必须是整数且px==py
bool all_match = true ;
//
for (int i = 1; i < ratios.size(); ++i)
{
LL xx = ratios[i].x ;
LL yy = ratios[i].y ;
LL px = getPow(xx,fx) ;
LL py = getPow(yy,fy) ;
if(px == -1 || py == -1 || px != py)
{
all_match = false ;
break ;
}
}
if(all_match)
{
Ratio ans = Ratio(fx,fy) ;
cout << ans.x << "/" << ans.y << endl ;
}
return 0 ;
}
return 0 ;
}
//优化 + 完善
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
int N;
LL data[100];
//结构体
struct Ratio
{
LL x, y;
Ratio(LL _x, LL _y) : x(_x), y(_y)
{
LL _gcd = gcd(x, y);
x /= _gcd;
y /= _gcd;
}
LL gcd(LL a, LL b)
{
if (b == 0)return a;
return gcd(b, a % b);
}
};
vector<Ratio> ratios;
map<LL, map<LL,LL> > all_ex;//all_ex[x][pow]==x开pow次方
map<LL, map<LL,LL> > all_log;//all_log[x][y]==log_y_x,y的多少次方是x?
void init() //预处理
{
for (int i = 2; i < 1e6; ++i)
{//底数
LL cur=(LL)i*i;
int pow=2;
while(cur<1e12)
{
all_ex[cur][pow]=i;
all_log[cur][i]=pow;
pow++;
cur*=i;
}
}
}
/**
* 对x开pow次方
* @param x
* @param pow
* @return
*/
LL extract(LL x,LL pow)
{
if(pow==1)return x;
if(x==1)return 1;
if(all_ex[x].find(pow)!=all_ex[x].end())//意味着x可以开pow整数次方
return all_ex[x][pow];
else
return -1;
}
/**
* 求log_base_x
* @param base
* @param x
* @return
*/
LL log(LL base,LL x)
{
if(base==x)return 1;
if(all_log[x].find(base)!=all_log[x].end())//意味着可以得打一个k,base的k次方是x
return all_log[x][base];
return -1;
}
int main(int argc, const char *argv[])
{
init();
freopen("/Users/zhengwei/CLionProjects/lanqiaobei2019/2016_C_A/data10/in8.txt","r",stdin);
//处理输入
scanf("%d", &N);
for (int i = 0; i < N; ++i)
{
scanf("%lld", &data[i]);
}
//排序
sort(data, data + N);
//处理只有两项的特殊情况
if(N==2)
{
Ratio ans = Ratio(data[1], data[0]);
cout << ans.x << "/" << ans.y << endl;
return 0;
}
//求两两比值,以分数形式存储,vector
for (int i = 0; i < N - 1; ++i)
{
if (data[i + 1] != data[i])//去重
ratios.push_back(Ratio(data[i + 1], data[i]));
}
//对第一个比值开1~..pow(极限为40).次方,作为基数,如果这个基数也是其他比值的基数的话,该基数就是答案
for (int pow = 1; pow <= 40; ++pow)
{
Ratio ra0 = ratios[0];
LL x = ra0.x;
LL y = ra0.y;
LL base_x = extract(x, pow);//对x开pow次方,作为基数,去尝试
LL base_y = extract(y, pow);//对y开pow次方,作为基数,去尝试
if (base_x == -1 || base_y == -1)continue;//开不出,continue
//能开:就要去确认所有比值的分子是fx的整数次方,所有比值的分母是fy的整数次方
//计px=getPow(xx,base_x),py=getPow(yy,base_y),要求必须是整数且px==py
bool all_match = true;
for (int i = 1; i < ratios.size(); ++i)
{
LL xx = ratios[i].x;
LL yy = ratios[i].y;
LL log_x = log(base_x,xx);
LL log_y = log(base_y,yy);
if(base_y==1&&yy==1)log_y=log_x;
if (log_x == -1 || log_y == -1 || log_x != log_y) {
all_match = false;
break;
}
}
if (all_match)
{
Ratio ans = Ratio(base_x, base_y);
cout << ans.x << "/" << ans.y << endl;
return 0;
}
}
return 0;
}
总结
//【2016年B组C++小结】 /******************
-
01【结果填空】煤球数目 :枚举+简单计算
-
02【结果填空】生日蜡烛 :等差数列求和
-
03【结果填空】凑算式 :全排列
-
04【代码填空】快速排序 :裸题
-
05【代码填空】抽签 :递归,明确参数的含义及参数的变化方向
-
06【填空填空】方格填数 :全排列 + check
-
07【结果填空】剪邮票(**) :dfs解决不了T型组合,全排列+dfs求矩阵中的连通块
-
08【编程题】四平方和 :枚举+优化
-
09【编程题】交换瓶子(**) :贪心
-
10【编程题】最大比例(*) :数论、等比数列、预处理 ********************/