第七届省赛题目
注意
- 简单的题目,只是写了一个函数实现功能,对于复杂的题目,会给出全部代码
1
-
题目
网友年龄
某君新认识一网友。
当问及年龄时,他的网友说:
“我的年龄是个2位数,我比儿子大27岁,
如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦. -
代码
void test01()
{
int num = 0;
for(int i=0;i<=9;i++)
{
for(int j=0;j<i;j++)
{
if( 9*(i-j) == 27 )
{
num++;
//printf("%d, %d\n", 10*i+j, 10*j+i);
}
}
}
printf("num : %d\n", num);
}
2
-
题目
生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的? 注意:这道题不需要进行两层循环即可。
-
代码
void test02()
{
int sum = 0;
int si = 0, ei = 0;
int goal = 236;
while( sum != goal )
{
if( sum < goal )
{
ei++;
sum += ei;
}
else if( sum > goal )
{
sum -= si;
si++;
}
}
printf("si : %d, ei : %d\n", si, ei);
}
3
-
题目
方格填数
如下的10个格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
(如果显示有问题,也可以参看【图1.jpg】)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案? 思路:DFS
-
代码
#include <stdio.h>
int num[3][4];
int sum = 0;
bool isFilled[10];
int abs(int n)
{
return n >= 0 ? n : -n;
}
// 在num[r][c]处防止i符合规则则返回true
bool isLegal(int r, int c, int val)
{
if( r == 0 && c == 0 )
return true;
else if( r == 0 )
return abs(val-num[r][c-1]) > 1;
else if( c == 0 )
return abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c+1])>1;
else if( c != 3 )
return abs(val-num[r][c-1]) > 1 && abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c-1])>1 && abs(val-num[r-1][c+1])>1;
else
return abs(val-num[r][c-1]) > 1 && abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c-1])>1;
}
void dfs(int r, int c)
{
if( r == 2 && c == 3 )
{
sum++;
return;
}
for(int i=0;i<=9;i++)
{
if( !isFilled[i] && isLegal(r, c, i) )
{
num[r][c] = i;
isFilled[i] = true;
dfs( r + (c+1)/4, (c+1)%4 );
isFilled[i] = false;
}
}
}
int main()
{
num[0][0] = -10;
num[2][3] = -10;
for(int i=0;i<10;i++)
isFilled[i] = false;
dfs( 0, 1 );
printf("%d\n", sum);
return 0;
}
4
-
题目
快排的填空实现
-
代码
#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 ); // 将最初的基准值与之后返回的下标对应的数据做对比
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;
}
5
-
题目
消除尾一
下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
如果最后一位是0,则原数字保持不变。
如果采用代码中的测试数据,应该输出:
00000000000000000000000001100111 00000000000000000000000001100000
00000000000000000000000000001100 00000000000000000000000000001100 -
代码
#include <stdio.h>
void f(int x)
{
int i;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf(" ");
x = x&(x+1);
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf("\n");
}
int main()
{
f(103);
f(12);
return 0;
}
6
-
题目
寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果显示不出来,可以参见【图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
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案? -
代码
#include <stdio.h>
bool isUsed[14];
int num[4][3];
int sum = 0;
// 判断第几行最后一个值填入这个是否正确
bool right( int r, int val )
{
switch(r)
{
case 0:
return num[r][0] + num[r][1] == val;
break;
case 1:
return num[r][0] - num[r][1] == val;
break;
case 2:
return num[r][0] * num[r][1] == val;
break;
case 3:
return val * num[r][1] == num[r][0];
break;
default:
return false;
}
}
void dfs( int r, int c )
{
if( r == 4 )
{
sum++;
if( sum <= 3 )
{
for(int i=0;i<4;i++)
{
for(int j=0;j<3;j++)
printf("%4d", num[i][j]);
printf("\n");
}
}
printf("\n");
return;
}
for(int i=1;i<=13;i++)
{
// 该数没有被使用
if( !isUsed[i] )
{
isUsed[i] = true;
// 是计算的结果,则需要判断一下
if( c != 2 || right(r, i) )
{
num[r][c] = i;
dfs( r+(c+1)/3, (c+1)%3 );
}
isUsed[i] = false;
}
}
}
int main()
{
for(int i=1;i<14;i++)
isUsed[i] = false;
dfs( 0, 0 );
printf("%d\n", sum);
}
7
-
题目
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。 注:有人用dfs求解,我没怎么看懂23333,参考链接在这:http://blog.csdn.net/kavu1/article/details/51130029
-
代码
#include <stdio.h>
bool map[3][4];
int sum = 0;
int idx[5];
int abs( int a )
{
return a >= 0 ? a : -a;
}
bool connect(int a, int b)
{
int r1 = a/4, c1 = a%4;
int r2 = b/4, c2 = b%4;
return abs(r1-r2)+abs(c1-c2) == 1;
}
bool match()
{
bool ret = false;
for(int i=0;i<5;i++)
{
ret = false;
for(int j=0;j<5;j++)
{
if( connect(idx[i],idx[j]) )
{
ret = true;
break;
}
}
if( !ret ) // 如果无法连接,则退出并返回
break;
}
return ret;
}
int main()
{
// 随机选取5个点,看是否能够
for(int i1=0;i1<12;i1++)
{
idx[0] = i1;
for(int i2=i1+1;i2<12;i2++)
{
idx[1] = i2;
for( int i3=i2+1;i3<12;i3++ )
{
idx[2] = i3;
for(int i4=i3+1;i4<12;i4++)
{
idx[3] = i4;
for(int i5=i4+1;i5<12;i5++)
{
idx[4] = i5;
if( match() )
{
sum++;
}
}
}
}
}
}
printf("ans : %d\n", sum);
return 0;
}
8
-
题目
四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多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 -
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int num[5];
int goal = 0;
int number = 0;
void dfs(int n, int sum)
{
if( number != 0 )
exit(0);
if( sum > goal || n > 5 )
return;
if( n == 5 )
{
if( sum == goal )
{
number++;
for( int i=1;i<5;i++ )
printf("%d ", num[i]);
printf("\n");
}
return;
}
// 这是不等于5的情况
if( sum == goal )
return;
num[n] = num[n-1];
int tmp = sum;
while( tmp < goal )
while( tmp < goal )
{
tmp = sum+num[n]*num[n];
dfs( n+1, tmp );
num[n]++;
}
}
int main()
{
scanf("%d", &goal);
dfs(1, 0);
return 0;
}
9
-
题目
密码脱落
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABDCDCBABC
则程序应该输出:
3 -
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
char s[1020];
int min_len = 9999;
int s_len = 0;
void dfs(int l, int r, int len)
{
if( l>=r )
{
if( min_len > len )
min_len = len;
return;
}
// 对称则继续检测
if( s[l] == s[r] )
dfs( l+1, r-1, len );
// 2种情况
else
{
dfs(l+1, r, len+1);
dfs(l, r-1, len+1);
}
}
int main()
{
gets( s );
s_len = strlen( s );
dfs( 0, s_len-1, 0 );
printf("min len : %d\n", min_len);
return 0;
}
10
-
题目
最大比例
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 - 参考链接:http://www.aichengxu.com/cyvyan/6607933.htm
- 思路:这道题其实是找出所有相邻数的最大公约数的最大公约数,首先对数据进行排序,然后去除重复的数字,最后求出相邻数据被的最大公约数除过之后的数。原文的链接中的做法无法对
16,24,81
的测试数据正确求解(我认为正确的解为3/2
,原文链接代码得到的是9/4
) - 注意:long long的数据输入与输出需要使用%lld,否则在输出时,会影响后面数据的输出,在输入时,对于很大的数据,无法读取。
-
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int N;
long long bonus[100];
long long res[100], p1[100], p2[100];
long long num1, num2;
void sort()
{
long long tmp;
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
if( bonus[j] < bonus[i] )
{
tmp = bonus[j];
bonus[j] = bonus[i];
bonus[i] = tmp;
}
}
}
}
void removeSame()
{
int k = 1;
res[0] = bonus[0];
for(int i=1;i<N;i++)
{
if( bonus[i] == bonus[i-1] )
continue;
res[k++] = bonus[i];
}
N = k;
}
long long gcd(long long a, long long b)
{
long long t;
if( b == 0 )
return a;
else
return gcd( b, a%b );
}
long long max(long long a, long long b)
{
return a >= b ? a : b;
}
long long min(long long a, long long b)
{
return a <= b ? a : b;
}
void solve()
{
int tmp;
int k;
if( N == 1 )
{
num1 = 1;
num2 = 1;
return;
}
else if( N == 2 )
{
tmp = gcd( res[1], res[0] );
num1 = res[1] / tmp;
num2 = res[0] / tmp;
return;
}
else
{
k = 0;
long long g,g1,g2;
for(int i=1;i<N;i++)
{
tmp = gcd( res[i], res[i-1] );
p1[k] = res[i] / tmp;
p2[k] = res[i-1] / tmp;
k++;
}
}
double t = 999999; // 存储最小的公约数
long long t1, t2, tt1, tt2, max_tmp, min_tmp;
long long max_p1, max_p2, min_p1, min_p2;
for(int i=0;i<N-1;i++)
{
for(int j=i+1;j<N-1;j++)
{
if( p1[i]*p2[j] == p1[j]*p2[i] )
{
t1 = p1[i];
t2 = p2[i];
}
else
{
max_p1 = max( p1[i], p1[j] );
max_p2 = max( p2[i], p2[j] );
min_p1 = min( p1[i], p1[j] );
min_p2 = min( p2[i], p2[j] );
max_tmp = max_p1;
min_tmp = min_p1;
max_p1 = max( min_tmp, max_tmp/min_tmp );
min_p1 = min( min_tmp, max_tmp/min_tmp );
max_tmp = max_p2;
min_tmp = min_p2;
max_p2 = max( min_tmp, max_tmp/min_tmp );
min_p2 = min( min_tmp, max_tmp/min_tmp );
t1 = gcd( max_p1, min_p1 );
t2 = gcd( max_p2, min_p2 );
}
// 在之前的程序中可知p1>p2
if( 1.0*t1/t2 < t )
{
t = 1.0*t1/t2;
tt1 = t1;
tt2 = t2;
}
}
}
tmp = gcd(tt1, tt2);
num1 = tt1 / tmp;
num2 = tt2 / tmp;
}
int main()
{
scanf("%d", &N);
for(int i=0;i<N;i++)
scanf("%lld", &bonus[i]);
sort();
removeSame();
solve();
printf("%lld/%lld\n", num1, num2);
return 0;
}