X星球日报和我们地球的城市早报是一样的,
都是一些单独的纸张叠在一起而已。每张纸印有4版。
比如,某张报纸包含的4页是:5,6,11,12,
可以确定它应该是最上边的第2张报纸。
我们在太空中捡到了一张X星球的报纸,4个页码分别是:
1125,1126,1727,1728
请你计算这份报纸一共多少页(也就是最大页码,并不是用了几张纸哦)?
请填写表示总页数的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【分析】找规律
n页的报纸,页码排列遵从如下规律:
1 3 5 7 …… …… | …… …… n-7 n-5 n-3 n-1
2 4 6 8 …… …… | …… …… n-6 n-4 n-2 n
其中页码1 2 n-1 n在同一张报纸上,页码3 4 n-3 n-2在同一张报纸上,页码5 6 n-5 n-4在同一张报纸上,以此类推。
这里 | 为“对称轴”,可以想象成装订报纸的“钉子”。因此如果确定了一张报纸上的4个页码a, b, c, d,便可确定:
最大页码maxpage=(a+b+c+d-1-2)/2+1。
#include <stdio.h>
int main()
{
int maxpage=(1125+1126+1727+1728-1-2)/2+1;
printf("%d\n",maxpage);
return 0;
}
【答案】2852
2. (5')煤球数目
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
....
如果一共有100层,共有多少个煤球?
请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【分析】循环+枚举
依次枚举各层,第i层煤球数=(i*(i+1))/2。
#include <stdio.h>
int main()
{
int level;
int sum=0;
for(level=1;level<=100;level++)
{
sum+=((level*(level+1))/2);
printf("%d\n",sum);
}
printf("%d\n",sum);
return 0;
}
【答案】171700
3. (7')平方怪圈如果把一个正整数的每一位都平方后再求和,得到一个新的正整数。
对新产生的正整数再做同样的处理。
如此一来,你会发现,不管开始取的是什么数字,
最终如果不是落入1,就是落入同一个循环圈。
请写出这个循环圈中最大的那个数字。
请填写该最大数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【分析】数位基本操作(分离&逐位累加求和)+找规律
根据题意,明确以下两点:
1°不管开始取的是什么数字-->选定范围[a, b]内的数,可任选(保证区间内有一定量的数,并且有一部分能落入循环圈)
2°最终如果不是落入1,就是落入同一个循环圈-->对落入循环圈的数,"每一位都平方后再求和,得到一个新的正整数"的操作可以无休止的进行。
因此,我们不妨选定区间[1, 1000],对此区间内的数进行上述操作,从而"观察"循环圈,以确定循环圈中最大的数。
#include <stdio.h>
#define maxcur 30 //最大循环操作次数
int main()
{
int i;
int temp,cur,sum;
for(i=1;i<=1000;i++)
{
temp=i;
cur=1;
printf("%d",i);
while(temp!=1 && cur<=30) //落入1或落入循环圈
{
sum=0;
//重复操作
while(temp)
{
sum+=(temp%10)*(temp%10);
temp/=10;
}
temp=sum;
cur++;
printf("->%d",temp);
}
printf("\n");
}
return 0;
}
【答案】145
4. (11')打印方格
小明想在控制台上输出 m x n 个方格。
比如 10x4的,输出的样子是:
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
(如果显示有问题,可以参见【图1.jpg】)
以下是小明写的程序,请你分析其流程,填写划线部分缺少的代码。
#include <stdio.h>
//打印m列,n行的方格
void f(int m, int n)
{
int row;
int col;
for(row=0; row<n; row++){
for(col=0; col<m; col++) printf("+---");
printf("+\n");
for(col=0; col<m; col++) printf("| ");
printf("|\n");
}
printf("+");
____________________________________; //填空
printf("\n");
}
int main()
{
f(10,4);
return 0;
}
注意:仅仅填写划线部分缺少的内容,不要添加任何已有内容或说明性文字。
【分析】打印图案
没什么好说的,填空处为打印方格下边界。
#include <stdio.h>
//打印m列,n行的方格
void f(int m, int n)
{
int row;
int col;
for(row=0; row<n; row++){
for(col=0; col<m; col++) printf("+---");
printf("+\n");
for(col=0; col<m; col++) printf("| ");
printf("|\n");
}
printf("+");
for(col=0; col<m; col++) printf("---+"); //填空
printf("\n");
}
int main()
{
f(10,4);
return 0;
}
【答案】for(col=0; col<m; col++) printf("---+")
5. (13')快速排序
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#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;
int j = r + 1;
int x = a[p];
while(1){
while(i<r && a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
swap(a,i,j);
}
______________________;
return j;
}
void quicksort(int a[], int p, int r)
{
if(p<r){
int q = partition(a,p,r);
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;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
【分析】快速排序算法
#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;
int j = r + 1;
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); //填空-下标j处的数将整个序列划分为两部分
return j;
}
void quicksort(int a[], int p, int r)
{
if(p<r){
int q = partition(a,p,r);
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;
}
【答案】swap(a,p,j)
6. (15')凑算式
B DEF
A + --- + ------- = 10
C GHI
(如果显示有问题,可以参见【图1.jpg】)
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
【分析】循环+枚举
A~I代表1~9 9个数字,因此可使用全排列代替传统的9重循环枚举,并且不需手动实现去重,更加高效。
此外,B/C和DEF/GHI不一定是整数,因此在计算A+ B/C + DEF/GHI之和时,结果与10需进行实数(浮点数)的大小比较,以避免精度问题影响结果。
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int a[9]={1,2,3,4,5,6,7,8,9};
int ans=0;
int main()
{
int i;
int n1,n2,n3,n4,n5;
double result;
do
{
n1=a[0];
n2=a[1];
n3=a[2];
n4=a[3]*100+a[4]*10+a[5];
n5=a[6]*100+a[7]*10+a[8];
result=n1+n2*1.0/n3+n4*1.0/n5;
if(fabs(result-10)<1e-8)
{
cout<<n1<<"+"<<n2<<"/"<<n3<<"+"<<n4<<"/"<<n5<<"=10"<<endl;
ans++;
}
} while(next_permutation(a,a+9));
cout<<ans<<endl;
return 0;
}
【答案】29
7. (19')寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果显示不出来,可以参见【图1.jpg】)
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【分析】DFS+剪枝
因题意及数据规模(1~13)的限制,搜索填数时需"剪枝",也就是及时排除不符合要求的情况。
#include <stdio.h>
#include <string.h>
int a[12]; //待填空的方块
int used[14]; //1~13 13个数字的使用标记
int ans=0; //方案总数
//从第cur个方块开始填数
void dfs(int cur)
{
int i;
//终点:方块均已填入数字
if(cur==12)
{
printf("%d + %d = %d\n",a[0],a[1],a[2]);
printf("%d - %d = %d\n",a[3],a[4],a[5]);
printf("%d * %d = %d\n",a[6],a[7],a[8]);
printf("%d / %d = %d\n",a[9],a[10],a[11]);
printf("\n");
ans++;
return;
}
//依次试探1~13 13个数,并填入方块
for(i=1;i<=13;i++)
{
if(!used[i])
{
//剪枝:方案不符合要求的情形
if(cur==2 && a[0]+a[1]!=i)
continue;
if(cur==5 && a[3]-a[4]!=i)
continue;
if(cur==8 && a[6]*a[7]!=i)
continue;
if(cur==11 && (!(a[9]%a[10]==0 && a[9]/a[10]==i)))
continue;
used[i]=1;
a[cur]=i;
dfs(cur+1);
used[i]=0;
}
}
}
int main()
{
//初始化标记:1~13 13个数字未使用
memset(used,0,sizeof(used));
//从第0个方块开始填数
dfs(0);
printf("%d\n",ans);
return 0;
}
【答案】64
8. (21')冰雹数
任意给定一个正整数N,
如果是偶数,执行: N / 2
如果是奇数,执行: N * 3 + 1
生成的新的数字再执行同样的动作,循环往复。
通过观察发现,这个数字会一会儿上升到很高,
一会儿又降落下来。
就这样起起落落的,但最终必会落到“1”
这有点像小冰雹粒子在冰雹云中翻滚增长的样子。
比如N=9
9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
可以看到,N=9的时候,这个“小冰雹”最高冲到了52这个高度。
输入格式:
一个正整数N(N<1000000)
输出格式:
一个正整数,表示不大于N的数字,经过冰雹数变换过程中,最高冲到了多少。
例如,输入:
10
程序应该输出:
52
再例如,输入:
100
程序应该输出:
9232
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
【分析】经典“3n+1”问题,在其基础上维护变换过程中的最大值即可。需要注意精度问题,使用long long int。
#include <stdio.h>
typedef long long ll;
ll N,ret=1;
int main()
{
ll i,temp;
scanf("%lld",&N);
for(i=1;i<=N;i++)
{
temp=i;
while(temp!=1)
{
if(temp%2==0)
temp/=2;
else
temp=3*temp+1;
ret=(temp>ret)?temp:ret;
}
}
printf("%lld\n",ret);
return 0;
}
9. (25')卡片换位
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子
+---+---+---+
| A | * | * |
+---+---+---+
| B | | * |
+---+---+---+
在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。
还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。
输入格式:
输入两行6个字符表示当前的局面
输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)
例如,输入:
* A
**B
程序应该输出:
17
再例如,输入:
A B
***
程序应该输出:
12
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
10. (31')密码脱落
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABDCDCBABC
则程序应该输出:
3
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。