蓝桥杯省赛训练3->2014年第五届蓝桥杯省赛A组(与B组相同部分略去)

1.猜年龄
小明带两个妹妹参加元宵灯会。别人问她们多大了,她们调皮地说:“我们俩的年龄之积是年龄之和的6倍”。小明又补充说:“她们可不是双胞胎,年龄差肯定也不超过8岁啊。”

请你写出:小明的较小的妹妹的年龄。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main(){
	for(int i=1;i<=20;i++){
		for(int j=i;j<=i+8;j++){
			if(i*j==6*(i+j)){
				cout<<i<<' '<<j<<endl;
				return 0;
			}
		}
	}
}
//10
3.神奇算式
由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如: 
210 x 6 = 1260 
8 x 473 = 3784
27 x 81 = 2187 都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int judge(int a,int b,int c){
    int count=0;
	int book[10];
	memset(book,0,sizeof(book));
	if(c<=1000||c>=10000){
		return 0;
	}
	while(a){
		if(book[a%10]){
			return 0;
		}
		book[a%10]=1;
		count++;
		a/=10;
	}
	while(b){
		if(book[b%10]){
			return 0;
		}
		book[b%10]=1;
		count++;
		b/=10;
	}
	if(count!=4){
		return 0;
	}
	while(c){
		if(!book[c%10]){
			return 0;
		}
		book[c%10]=0;
		c/=10;
	}
	return 1;
}
int main(){
	int a[4];
	int num1,num2,count=0;
	for(num1=1;num1<=100;num1++){
		for(num2=num1+1;num2<=9999;num2++){
			if(judge(num1,num2,num1*num2)){
				count++;
			}
		}
	}
	cout<<count<<endl;
	return 0;
}
//12
5.锦标赛
如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发。
如图【1.png】所示,8个选手的锦标赛,先两两捉对比拼,淘汰一半。优胜者再两两比拼...直到决出第一名。
第一名输出后,只要对黄色标示的位置重新比赛即可。
下面的代码实现了这个算法(假设数据中没有相同值)。
代码中需要用一个数组来表示图中的树(注意,这是个满二叉树,不足需要补齐)。它不是存储数据本身,而是存储了数据的下标。   
第一个数据输出后,它所在的位置被标识为-1

//重新决出k号位置,v为已输出值 
void pk(int* a, int* b, int n, int k, int v){
int k1 = k*2 + 1;
int k2 = k1 + 1;

if(k1>=n || k2>=n){
b[k] = -1;
return;
}

if(b[k1]==v) 
pk(a,b,n,k1,v);
else
pk(a,b,n,k2,v);

//重新比较
if(b[k1]<0){
if(b[k2]>=0)
b[k] = b[k2]; 
else
b[k] = -1;
return;
}

if(b[k2]<0){
if(b[k1]>=0)
b[k] = b[k1]; 
else
b[k] = -1;
return;
}

if(______________________) //填空
b[k] = b[k1];
else
b[k] = b[k2];
}
//对a中数据,输出最大,次大元素位置和值 
void f(int* a, int len){
int n = 1;
while(n<len) n *= 2;

int* b = (int*)malloc(sizeof(int*) * (2*n-1));
int i;
for(i=0; i<n; i++){ 
if(i<len) 
b[n-1+i] = i;
else
b[n-1+i] = -1;
}

//从最后一个向前处理
for(i=2*n-1-1; i>0; i-=2){
if(b[i]<0){
if(b[i-1]>=0)
b[(i-1)/2] = b[i-1]; 
else
b[(i-1)/2] = -1;
}
else{
if(a[b[i]]>a[b[i-1]])
b[(i-1)/2] = b[i];
else
b[(i-1)/2] = b[i-1];
}
}

//输出树根
printf("%d : %d\n", b[0], a[b[0]]);

//值等于根元素的需要重新pk
pk(a,b,2*n-1,0,b[0]);

//再次输出树根
printf("%d : %d\n", b[0], a[b[0]]);

free(b);
}
int main(){
int a[] = {54,55,18,16,122,17,30,9,58};
f(a,9);
}


//答案:a[b[k1]]>=a[b[k2]]

6.扑克序列
A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。
请填写出所有符合要求的排列中,字典序最小的那个。例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int judge(int c[],int a,int b){
	int i,j,loc1,loc2;
	for(i=0;i<8;i++){
		if(c[i]==a){
			loc1=i;
			break;
		}
	}
	for(j=i+1;j<8;j++){
		if(c[j]==a){
			loc2=j;
			break;
		}
	}
	if(loc2-loc1==b+1){
		return 1;
	}
	return 0;
}
int main(){
	int a[8]={2,2,3,3,4,4,5,5};
	do{
		if(judge(a,5,1)&&judge(a,2,2)&&judge(a,3,3)&&judge(a,4,4)){
			break;
		}
	}while(next_permutation(a,a+8));
	for(int i=0;i<8;i++){
		printf("%d",a[i]);
	}
	cout<<endl;
	return 0;
}
//23425354   题目的意思为字母的字典序大
//即:2342A3A4
9.标题:斐波那契
斐波那契数列大家都非常熟悉。它的定义是:
f(x) = 1      .... (x=1,2)

f(x) = f(x-1) + f(x-2)      .... (x>2)
对于给定的整数 n 和 m,我们希望求出:
f(1) + f(2) + ... + f(n)  的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
 但这个数字依然很大,所以需要再对 p 求模。
【数据格式】
输入为一行用空格分开的整数 n m p (0 < n, m, p < 10^18)
输出为1个整数
例如,如果输入:
2 3 5
程序应该输出:
0
再例如,输入:
15 11 29
程序应该输出:

25


//目前只过了部分测试点......待完善

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long LL;
LL n,m,p,MOD,re;
struct node{
	int m[2][2];
};
struct node Cal(struct node a,struct node b){
	struct node c;
	memset(c.m,0,sizeof(c.m));
	for(int i=0;i<2;i++){
		for(int j=0;j<2;j++){
			if(a.m[i][j]){
				for(int t=0;t<2;t++){
					c.m[i][t]=c.m[i][t]+a.m[i][j]*b.m[j][t];
				}
			}
		}
	}
	return c;
}
struct node quick_pow(struct node a,LL cnt){
	struct node e;
	memset(e.m,0,sizeof(e.m));
	e.m[0][0]=e.m[1][1]=1;
	if(cnt==0){
		return e;
	}
	if(cnt==1){
		return a;
	}
	while(cnt){
		if(cnt&1){
			e=Cal(e,a);
		}
		a=Cal(a,a);
		cnt=cnt>>1;
	}
	return e;
}
int main(){
	LL top;
	struct node mat,t;
	scanf("%lld%lld%lld",&n,&m,&p);
	mat.m[0][1]=mat.m[1][0]=mat.m[1][1]=1;
	mat.m[0][0]=0;
	t=quick_pow(mat,m-1);
	MOD=t.m[0][0]+t.m[0][1];
	for(LL i=1;i<=n;i++){
		t=quick_pow(mat,i-1);
		re=(re+t.m[0][0]+t.m[0][1])%MOD;
	}
	printf("%lld\n",re%p);
	return 0;
}
10.波动数列
观察这个数列:1 3 0 2 -1 1 -2 ...
这个数列中后一项总是比前一项增加2或者减少3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?

【数据格式】
输入的第一行包含四个整数 n s a b,含义如前面说述。
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。
例如,输入:
4 10 2 3
程序应该输出:
2
【样例说明】
这两个数列分别是2 4 1 3和7 4 1 -2。
【数据规模与约定】
对于10%的数据,1<=n<=5,0<=s<=5,1<=a,b<=5;
对于30%的数据,1<=n<=30,0<=s<=30,1<=a,b<=30;
对于50%的数据,1<=n<=50,0<=s<=50,1<=a,b<=50;
对于70%的数据,1<=n<=100,0<=s<=500,1<=a, b<=50;
对于100%的数据,1<=n<=1000,-1,000,000,000<=s<=1,000,000,000,1<=a, b<=1,000,000。

//动态规划

待写......


可见,A组编程大题的后一两道还是比较难的,对于B组选手来说确实要下功夫才能和211,985的大牛们相比......


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值