[蓝桥杯]2016蓝桥省赛B组题目及详解

/*———————————————————————————————————————————————————————————
【结果填空题】T1 (分值: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 = ; //
int plus = ; //
long sum = ;
for (int k = ; k <= ; ++k)
{
sum += (pre+plus) ;
pre = pre + plus ;//sum+=pre
plus++ ;
}
cout << sum << endl ; return ;
}
//结果:171700 /*———————————————————————————————————————————————————————————
【结果填空题】T2 (分值:5)
题目:生日蜡烛 某君从某年开始每年都举办一次生日party,
并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
————————————————————————————————————————————————————————————*/
//
/*
思路:236 i ~ j
for(i:100)
for(j:100)
等差数列求和:(i+j)/2*(j-i-1)
(a0+a0*(n-1)*d/2)*n*/ #include<iostream>
using namespace std ;
int main()
{
//枚举两个年龄
for (int i = ; i < ; ++i)
{
for (int j = i; j < ; ++j)
{
if((i*j)*(j-i-)/==)
cout << i << " "<< j << endl ;
}
} //枚举生日举办次数
for (int i = ; i < ; ++i)
{
int t = i*(i-)/ ;
if((-t)%i==)
{
//输出首项
cout << (-t)/i << " " << i << endl ;
}
} return ;
} /*———————————————————————————————————————————————————————————
【结果填空题】T3 (分值: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<math.h> using namespace std ;
int a[] = {,,,,,,,,} ;
int ans ;
bool check()
{
int x = a[] * + a[] * + a[] ;
int y = a[] * + a[] * + a[] ;
if((a[]*y + a[]*x) % (y*a[])== && a[]
+ (a[]*y + a[]*x)/(y*a[]==)) return true ;
return false ;
} //递归回溯生成全排列 适用于无重复元素的情况
//考虑前k位,前面已经排定
void f(int k)
{
if(k==)
{
//其中一种排列已经生成
if(check()) ans++ ;
}
//从k往后的每个数字都可以放在k位
for (int i = k; i < ; ++i)
{
{int t=a[i]; a[i]=a[k]; a[k]=t;}
f(k+) ; //递归
{int t=a[i]; a[i]=a[k]; a[k]=t;} //回溯
}
} int main()
{
f() ;
cout << ans << endl ;
return ;
} //思路二 next_permutation() #include<iostream>
#include<math.h> using namespace std ;
int a[] = {,,,,,,,,} ;
int ans ;
bool check()
{
int x = a[] * + a[] * + a[] ;
int y = a[] * + a[] * + a[] ;
if((a[]*y + a[]*x) % (y*a[])== && a[]
+ (a[]*y + a[]*x)/(y*a[]==)) return true ;
return false ;
} int main()
{
do{
if(check()) ans++ ;
}while(next_permutation(a,a+)) ; cout << ans << endl ;
return ;
} /*———————————————————————————————————————————————————————————
【代码填空题】T4 (分值: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 + ; //j指向小于等于x ——>找小
int x = a[p];
while(){
while(i<r && a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
swap(a,i,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-);
quicksort(a,q+,r);
}
} int main()
{
int i;
int a[] = {,,,,,,,,,,,};
int N = ; quicksort(a, , N-); //排序 for(i=; i<N; i++)
printf("%d ", a[i]);
printf("\n"); return ;
} /*———————————————————————————————————————————————————————————
【代码填空题】T5 (分值: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缓冲字符串
*/ void f(int a[], int k, int m, char b[])
{
int i,j; if(k==N){
b[M] = ; //字符串结尾的标志
if(m==) {printf("%s\n",b); ans++ ;}
return;
}
//递归
for(i=; i<=a[k]; i++){ //试着将k国家,排除i人
for(j=; j<i; j++) b[M-m+j] = k+'A'; ////填充buf,有i人就填i个国家符号(k+'A')
/*代码填空处
f(a,k+1,m-i,b) ;
______________________; */
f(a,k+,m-i,b) ;
}
}
int main()
{
int a[N] = {,,,,,};
char b[BUF];
f(a,,M,b);
printf("%d\n",ans) ;
return ;
} /*———————————————————————————————————————————————————————————
【结果填空题】T6 (分值:19)
题目:方格填数
如下的10个格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+ (如果显示有问题,也可以参看【图1.jpg】)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案? 请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
————————————————————————————————————————————————————————————*/
// 全排列 + 检查
#include<iostream>
using namespace std ; int a[] = {,,,,,,,,,} ;
int ans ; void check()//检查
{
if(abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== || abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== || abs(a[] - a[])== ||
abs(a[] - a[])== || abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== || abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== || abs(a[] - a[])== ||
abs(a[] - a[])== ||
abs(a[] - a[])== || abs(a[] - a[])== || abs(a[] - a[])== || abs(a[] - a[])== ||)
return false ;
return true ;
} /*考虑第k个位置,一般从0开始*/
void f(int k)//递归函数
{
//出口
if(k==)
{
bool b = check() ; //检查
if(b)
ans++ ;
return ;
} for (int i = k; i < ; ++i)
//尝试将位置i与位置k交换,以此确定k位的值
{
int t = a[i] ;
a[i] = a[k] ;
a[k] = t ;
}
f(k+) ;
//回溯
{
int t = a[i] ;
a[i] = a[k] ;
a[k] = t ;
} } int main()
{
f() ; //初始化
cout << ans << endl ; return ;
} //思路2 使用二维数组
/* 3*4 ——> 5*6
-10-10-10-10-10
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
-10-10-10-10-10 */
#include<iostream>
using namespace std ; int a[][] ;
int vis[] ;
int ans ; bool check(int i ,int y) //检查
{
for (int x = x-; x<= i+; ++x)
{
for (int y = j-; y <= j+; ++y)
{
if(abs(a[x][y]-a[i][j])==)
return false ;
}
}
return true ;
} //全排列
void f(int k,int y)
{
if(x== & y == )
{
ans++ ;
return ;
}
//从0-9中抓一个
for (int i = ; i < ; ++i)
{
if(vis[i]==) //i没有没用过
{
a[x][y] = i ; //填数
if(!check(x,y)) //不合法,恢复并continue
{
a[x][y] = - ;
continue ;
}
vis[i] = ; if(y ==)
f(x+,) ; //换行
else
f(x,y+) ; //继续填右侧的格子
{
vis[i] = ;
a[x][y] = - ;
}
}
}
} //初始化
void init()
{
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
a[i][j] = - ; //初始化格式
}
}
} int main(int argc, char const *argv[])
{
init() ; //初始化
f(,) ; //递归调用
cout << ans <<endl ; //打印输出
return ;
}
/*本思路可以防止下标越界的问题*/ /*———————————————————————————————————————————————————————————
【结果填空题】T7 (分值: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[]); void dfs(int g[][], int i, int j); int main(int argc, const char *argv[]) {
int per[] = {, , , , , , , , , , , };
do {
if (check(per))
ans++;
} while (next_permutation(per, per + ));
cout << ans << endl;
return ;
} bool check(int arr[]) {
int g[][];
memset(g, , sizeof(g));
//将相应位置标注为1
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
if (arr[i * + j] == )g[i][j] = ;
}
}
// 经典连通块计算
int cnt = ;
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
if (g[i][j] == ) {
dfs(g, i, j);
cnt++;
}
}
}
return cnt == ;
} void dfs(int g[][], int i, int j) {
g[i][j] = ;
if (i + <= && g[i + ][j] == ) dfs(g, i + , j);
if (i - >= && g[i - ][j] == ) dfs(g, i - , j);
if (j + <= && g[i][j + ] == ) dfs(g, i, j + );
if (j - >= && g[i][j - ] == ) dfs(g, i, j - );
} //思路2:
#include <algorithm>
#include <iostream>
#include <set> using namespace std; int a[]={,,,,,,,,,,,};//它的每个排列代表着12选5的一个方案
int ans;
void dfs(int g[][],int i , int j){
g[i][j]=;
if(i->=&&g[i-][j]==)dfs(g,i-,j);
if(i+<=&&g[i+][j]==)dfs(g,i+,j);
if(j->=&&g[i][j-]==)dfs(g,i,j-);
if(j+<=&&g[i][j+]==)dfs(g,i,j+);
}
bool check(){
int g[][];
// 将某个排列映射到二维矩阵上
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
if(a[i*+j]==) g[i][j]=;
else g[i][j]=;
}
}
int cnt=;//连通块的数目
// g上面就有5个格子被标记为1,现在才用dfs做连通性检查,要求只有一个连通块
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
if(g[i][j]==){
dfs(g,i,j);
cnt++;
}
}
}
return cnt==;
}
set<string> s1;
void a2s(string &s){
for (int i = ; i < ; ++i) {
s.insert(s.end(),a[i]+'');
}
}
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==){
if(!isExist()&&check()){
ans++;
}
}
for (int i = k; i < ; ++i) {
{int t=a[i];a[i]=a[k];a[k]=t;}
f(k+);
{int t=a[i];a[i]=a[k];a[k]=t;}
}
}
int main(int argc, const char *argv[]) {
f();
printf("%d",ans);
//string _s;
//a2s(_s);
//cout<<_s<<endl;
return ;
} //思路3:
#include <algorithm>
#include <iostream> using namespace std; //它的每个排列代表着12选5的一个方案
int a[] = {, , , , , , , , , , , };
int ans; void dfs(int g[][], int i, int j)
{
g[i][j] = ;
if (i - >= && g[i - ][j] == )dfs(g, i - , j);
if (i + <= && g[i + ][j] == )dfs(g, i + , j);
if (j - >= && g[i][j - ] == )dfs(g, i, j - );
if (j + <= && g[i][j + ] == )dfs(g, i, j + );
} bool check(int path[])
{
int g[][];
// 将某个排列映射到二维矩阵上
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
if (path[i * + j] == ) g[i][j] = ;
else g[i][j] = ;
}
}
int cnt = ;//连通块的数目
// g上面就有5个格子被标记为1,现在才用dfs做连通性检查,要求只有一个连通块
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
if (g[i][j] == )
{
dfs(g, i, j);
cnt++;
}
}
}
return cnt == ;
} bool vis[]; void f(int k, int path[])
{
if (k == ) {
if (check(path))
{
ans++;
}
}
for (int i = ; i < ; ++i)
{
if (i>&&a[i]==a[i-]&&!vis[i-])continue;//现在准备选取的元素和上一个元素相同,但是上一个元素还没被使用 if(!vis[i]){//没有被用过的元素可以抓入到path
vis[i]=true;//标记为已访问
path[k]=a[i];//将a[i]填入到path[k]中
f(k + , path);//递归
vis[i]=false;//回溯
} }
} int main(int argc, const char *argv[])
{
int path[];
f(, path);
printf("%d", ans);
return ;
} /*———————————————————————————————————————————————————————————
【代码编程题】T8 (分值: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 ; int main()
{
scanf("%d",&N) ;
//
for (int c = ; c*c <= N/; ++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 = ; a*a<= N/; ++a)
{
for (int b = a; a*a+c*c <= N/; ++b)
{
if(cache.find(N-a*a+b*b)!=cache.end()) ;
int c = cache[N-(a*a+b*b+c*c)] ;
int d = int(sqrt(N-(a*a+b*b+c*c)) ;
printf("%d %d %d %d\n",a,b,c,d) ;
return ;
}
}
}
return ;
} /*———————————————————————————————————————————————————————————
【代码编程题】T9 (分值: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[];
int ans; int pos(int x)
{
for (int i = ; i <= n; ++i)
{
if (a[i] == x)return i;
}
return -;
} void swap(int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
} void printArr() {
for (int i = ; i <= n; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
} int main(int argc, const char *argv[])
{
// 处理输入
scanf("%d", &n);
for (int i = ; i <= n; ++i)
{
scanf("%d", &a[i]);
}
//遍历i:1-N
for (int i = ; 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 ;
} /*———————————————————————————————————————————————————————————
【代码编程题】T10 (分值: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[] ; 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==) return a ;
return gcd(b,a%b) ;
}
} ;
//存储比值
vector<Ratio> ratios ; int main()
{
//处理输入
scanf("%d",&n) ;
for (int i = ; i < N; ++i) //扫描输入数据
{
scanf("%lld",&data[i]) ;
} //排序
sort(data,data+N) ; //两两比值,以分数形式存储,vector
for (int i = ; i < N-; ++i)
{
if(data[i+]!=data[i])//去重
ratios.push_back(Ratio(data[i+],data[]i)) ;
} /*对第一个比值开1-..pow(极限为40)次方作为基数,
如果这个基数的分子、分母的k1
k2次方恰好是其他比值的分子分母的话,基数就是答案*/
for (int pow = ; pow <= ; ++pow)
{
Ratio ra0 = ratios[] ;
LL x = ra0.x ;
LL y = ra0.y ;
LL fx = extract(x,pow) ; //对
LL fy = extract(y,pow) ; //
if(fx==- |\ fy ==-) continue ; //开不出,continue
//能开,就要确认所有比值的分子是fx的整数次方,所有比值的分母是fy的整数次方
//计px=getPow(xx,fx),py=getPow(yy,fy),要求必须是整数且px==py bool all_match = true ;
//
for (int i = ; 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 == - || py == - || px != py)
{
all_match = false ;
break ;
}
}
if(all_match)
{ Ratio ans = Ratio(fx,fy) ;
cout << ans.x << "/" << ans.y << endl ;
}
return ;
} return ;
} //优化 + 完善
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map> using namespace std;
typedef long long LL;
int N;
LL data[]; //结构体
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 == )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 = ; i < 1e6; ++i)
{//底数
LL cur=(LL)i*i;
int pow=;
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==)return x;
if(x==)return ;
if(all_ex[x].find(pow)!=all_ex[x].end())//意味着x可以开pow整数次方
return all_ex[x][pow];
else
return -;
} /**
* 求log_base_x
* @param base
* @param x
* @return
*/ LL log(LL base,LL x)
{
if(base==x)return ;
if(all_log[x].find(base)!=all_log[x].end())//意味着可以得打一个k,base的k次方是x
return all_log[x][base];
return -;
} 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 = ; i < N; ++i)
{
scanf("%lld", &data[i]);
}
//排序
sort(data, data + N);
//处理只有两项的特殊情况
if(N==)
{
Ratio ans = Ratio(data[], data[]);
cout << ans.x << "/" << ans.y << endl;
return ;
} //求两两比值,以分数形式存储,vector
for (int i = ; i < N - ; ++i)
{
if (data[i + ] != data[i])//去重
ratios.push_back(Ratio(data[i + ], data[i]));
} //对第一个比值开1~..pow(极限为40).次方,作为基数,如果这个基数也是其他比值的基数的话,该基数就是答案
for (int pow = ; pow <= ; ++pow)
{
Ratio ra0 = ratios[];
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 == - || base_y == -)continue;//开不出,continue
//能开:就要去确认所有比值的分子是fx的整数次方,所有比值的分母是fy的整数次方
//计px=getPow(xx,base_x),py=getPow(yy,base_y),要求必须是整数且px==py
bool all_match = true;
for (int i = ; 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==&&yy==)log_y=log_x;
if (log_x == - || log_y == - || 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 ;
} }
return ;
} //【2016年B组C++小结】
/**********************************************************
* 01【结果填空】煤球数目 :枚举+简单计算
* 02【结果填空】生日蜡烛 :等差数列求和
* 03【结果填空】凑算式 :全排列
* 04【代码填空】快速排序 :裸题
* 05【代码填空】抽签 :递归,明确参数的含义及参数的变化方向
* 06【填空填空】方格填数 :全排列 + check
* 07【结果填空】剪邮票(**) :dfs解决不了T型组合,全排列+dfs求矩阵中的连通块
* 08【编程题】四平方和 :枚举+优化
* 09【编程题】交换瓶子(**) :贪心
* 10【编程题】最大比例(***) :数论、等比数列、预处理
**********************************************************/
上一篇:CSS文档流


下一篇:洛谷.4525.[模板]自适应辛普森法1(Simpson积分)