您的位置:首页 > 其它

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

2017-04-04 20:53 381 查看
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;
}
}
}
}
//103.神奇算式

由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;
}
//125.锦标赛

如果要在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 题目的意思为字母的字典序大
//即:2342A3A49.标题:斐波那契

斐波那契数列大家都非常熟悉。它的定义是:

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的大牛们相比......
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: