藍橋杯__省賽__第七屆__C/C++__大學A組
目錄
1、網友年齡
題意
某君新認識一網友。當問及年齡時,他的網友說:“我的年齡是個2位數,我比兒子大27歲,如果把我的年齡的兩位數字交換位置,剛好就是我兒子的年齡”。請你計算:網友的年齡一共有多少種可能情況?提示:30歲就是其中一種可能哦。請填寫表示可能情況的種數。注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
思路
列舉
C++程式碼
#include<iostream>
using namespace std;
int main()
{
int ans=0;//答案
for(int i=27;i<100;i++)//列舉父親的年齡
{
int j=i,t=0;//t存放i的兩位數交換後的數
while(j)
{
t=t*10+j%10;
j/=10;
}
if(i-t==27) ans++;//滿足條件就加一
}
printf("%d\n",ans);
return 0;
}
答案
7
2、生日蠟燭
題意
某君從某年開始每年都舉辦一次生日party,並且每次都要吹熄與年齡相同根數的蠟燭。現在算起來,他一共吹熄了236根蠟燭。請問,他從多少歲開始過生日party的?請填寫他開始過生日party的年齡數。注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
思路
列舉,考慮普通的情況,即每年都過一次生日,設開始過生日時的年齡為a1,經過n年的生日後吹熄了236根蠟燭,則由公差為1的等差數列求和公式得a1=(472-n(n-1))/(2n),因為a1和n是整數,因此可以通過列舉n的值來求a1。
C++程式碼
#include<iostream>
using namespace std;
int main()
{
for(int i=3;i<=100;i++)//i表示舉辦了i年Party
{
int temp=472-i*(i-1);
if(temp<0) break;
int temp2=2*i;
if(temp%temp2==0) printf("%d\n",temp/temp2);
}
return 0;
}
答案
26
3、方格填數
題意
如下的10個格子。填入0~9的數字。要求:連續的兩個數字不能相鄰(左右、上下、對角都算相鄰)。一共有多少種可能的填數方案?請填寫表示方案數目的整數。注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
思路
DFS
C++程式碼
#include<iostream>
#include<cmath>
using namespace std;
int a[5][6];//在3X4的陣列周圍填充一圈,這樣方便判斷
int d[8][2]={{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};//八個方向
int ans=0;//結果
bool vis[10];//vis[i]=true表示數字i已經被使用
void dfs(int i,int j)//考慮a[i][j]可以填的數
{
for(int k=0;k<10;k++)//遍歷0~9
if(!vis[k])
{
//如果數字k還沒有使用,就考慮此處是否能填k
bool flag=true;
for(int t=0;t<8;t++)//如果a[i][j]=k,考慮是否和它的八個方向的元素是否相差為1
{
int x=i+d[t][0];
int y=j+d[t][1];
if(abs(k-a[x][y])==1)
{
flag=false;//記錄此處不能填k
break;
}
}
if(flag)//如果此處能填數字k,就考慮填數字k
{
if(i==3&&j==3)//如果是最後一個元素,則結果加一
{
ans++;
return;
}
int nextj=j+1,nexti=i;//此處填了k,現在要填下一個位置了
if(nextj>4)//如果nextj>4說明第i行已經填完,開始填下一行
{
nextj-=4;
nexti++;
}
a[i][j]=k;//記錄此處填數字k
vis[k]=true;//標記數字k已經被使用了
dfs(nexti,nextj);
a[i][j]=-10;//如果此處不填k,考慮其他可能,就將vis[k]置為false
vis[k]=false;
}
}
}
int main()
{
for(int i=0;i<5;i++)
for(int j=0;j<6;j++)
a[i][j]=-10;//將陣列a[][]各個元素初始化為-10
dfs(1,2);//從(1,2)處開始深搜
printf("%d\n",ans);
return 0;
}
答案
1580
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);
}
______________________;
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)
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 = _______________________;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf("\n");
}
int main()
{
f(103);
f(12);
return 0;
}
注意:只填寫缺少的內容,不要書寫任何題面已有程式碼或說明性文字。
思路
位運算,消除x的末尾連續的1可以用x=x&(x+1)實現
答案
x&(x+1)
6、寒假作業
題意
現在小學的數學題目也不是那麼好玩的。看看這個寒假作業:
每個方塊代表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
C++程式
#include<iostream>
using namespace std;
bool vis[14];//vis[i]=false表示數字i還沒被使用
int a[13];//記錄這十二個數
int ans=0;//統計種類數
bool cal(int k,int i)//如果k是3的倍數,那麼就判斷第k個數為i是否符合
{
if(k==3)
return a[k-2]+a[k-1]==i;//是否滿足加法
else if(k==6)
return a[k-2]-a[k-1]==i;//是否滿足減法
else if(k==9)
return a[k-2]*a[k-1]==i;//是否滿足乘法
else
return a[k-2]==a[k-1]*i;//是否滿足除法
}
void dfs(int k)
{
if(k==13)//已經填了12個數,結果加一,並返回
{
ans++;
return;
}
for(int i=1;i<=13;i++)//遍歷13個數
{
if(!vis[i])//如果數字i還沒有被使用,就考慮讓a[k]=i
{
if(k%3!=0||cal(k,i))//如果k不是3的倍數,或者如果是3的倍數但是滿足等式
{
a[k]=i;//讓a[k]=i;
vis[i]=true;//數字i被使用
dfs(k+1);//填下一個數字
vis[i]=false;//考慮a[k]填其他數字
}
}
}
}
int main()
{
dfs(1);
printf("%d\n",ans);
return 0;
}
答案
64
7、剪郵票
題意
如圖1, 有12張連在一起的12生肖的郵票。現在你要從中剪下5張來,要求必須是連著的。(僅僅連線一個角不算相連)。比如,圖2,圖3中,粉紅色所示部分就是合格的剪取。請你計算,一共有多少種不同的剪取方法。
圖1
圖2
圖3
請填寫表示方案數目的整數。注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
思路
使用DFS選擇五個位置,然後再通過另一個DFS判斷這五個位置是否連線在一起。
C++程式
#include<iostream>
#include<cstring>
using namespace std;
bool vis[3][4];
bool temp[3][4];
int d[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int ans;
void dfs2(int x,int y)
{
temp[x][y]=false;
for(int i=0;i<4;i++)
{
int fx=x+d[i][0];
int fy=y+d[i][1];
if(0<=fx&&fx<3&&0<=fy&&fy<4&&temp[fx][fy])
dfs2(fx,fy);
}
}
//在標號大於等於start的位置中選擇一個位置作為第k個被裁剪的位置
void dfs1(int k,int start)
{
if(k==6)//已經挑選了五個位置了
{
//判斷這五個位置是否連線在一起
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)
temp[i][j]=vis[i][j];
int cnt=0;//發現裁剪的位置的次數
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)
{
if(temp[i][j])//(i,j)是被裁剪的位置
{
dfs2(i,j);
cnt++;
}
}
if(cnt==1) ans++;//cnt=1表示五個位置連線在一起,結果加一
return;
}
/*
在區間[start,7+k)中選擇一個位置作為第k個被裁剪的位置
第k個位置的標號要小於7+k,因為共12個標號(0..11),
第k個位置選擇後還差5-k個位置沒選擇,所以第k個位置的選擇的標號
要小於7+k
*/
for(int i=start;i<7+k;i++)
{
int x=i/4;
int y=i%4;
vis[x][y]=true;//考慮第k個位置為(x,y)
//在標號大於等於i+1的位置中選擇一個位置作為第k+1個被裁剪的位置
dfs1(k+1,i+1);
vis[x][y]=false;//考慮下一個位置為第k個被裁剪的位置
}
}
int main()
{
ans=0;
dfs1(1,0);
printf("%d\n",ans);
return 0;
}
答案
116
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
資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
思路
暴力列舉
C++程式
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int len=sqrt(n);
for(int i=0;i<=len;i++)
for(int j=i;j<=len;j++)
for(int k=j;k<=len;k++)
{
int t=n-i*i-j*j-k*k;
int temp=sqrt(t);
if(temp*temp==t&&temp>=k)
{
printf("%d %d %d %d\n",i,j,k,temp);
return 0;
}
}
return 0;
}
9、密碼脫落
題意
X星球的考古學家發現了一批古代留下來的密碼。
這些密碼是由A、B、C、D 四種植物的種子串成的序列。
仔細分析發現,這些密碼串當初應該是前後對稱的(也就是我們說的映象串)。
由於年代久遠,其中許多種子脫落了,因而可能會失去映象的特徵。
你的任務是:
給定一個現在看到的密碼串,計算一下從當初的狀態,它要至少脫落多少個種子,才可能會變成現在的樣子。
輸入一行,表示現在看到的密碼串(長度不大於1000)
要求輸出一個正整數,表示至少脫落了多少個種子。
例如,輸入:
ABCBA
則程式應該輸出:
0
再例如,輸入:
ABDCDCBABC
則程式應該輸出:
3
資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
思路
最長公共子序列,LCS。題目可以這樣來思考,新增最少的字元使得字串變成迴文字串,因此我們可以求出它和它的逆串的最長公共子序列的長度,那麼至少需要新增的字元數為它的長度-LCS(因為不同的數只有長度-LCS個,因此在對應的位置新增對應的字元即可)
C++程式
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int N=1005;
int dp[N][N];
//最長公共子序列
int LCS(string a,string b)
{
for(int i=0;i<=a.length();i++)
for(int j=0;j<=a.length();j++)
{
if(i==0||j==0)
dp[i][j]=0;
else if(a[i]==b[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
return dp[a.length()][b.length()];
}
int main()
{
string a,b;
cin>>a;
b=a;
reverse(b.begin(),b.end());
cout<<a.length()-LCS(a,b)<<endl;
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
資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
思路
輾轉相減。
對a1=q^x1、a2=q^x2、a3=q^x3、a4=q^x4、a5=q^x5、a6=q^x6、...
已知a1、a2、a3、a4、a5、a6、...的值,不知道q和x1、x2、x3、x4、x5、x6、...的值
求最大公比使得a1,a2,a3,a4,a5,a6,...是某個等比數列的某幾項(不一定是連續的幾項
這裡的下標不代表它們在等比數列中的位置)
易得所求的公比是 q^x,其中x=是x1,x2,x3,x4,x5,x6,...的約數
這樣任何一個數都能由q^x乘若干個q^x的得到,因此上面的數一定是等比數列的某一項
顯然,當x是x1,x2,x3,x4,x5,x6,...的最大公約數時q^x達到最大
求法:
定義Q(a,b)是由a,b唯一確定的最大比例,
那麼Q(a,b)=Q(q^x,q^y)=Q(q^x,q^(x-y))=Q(a,b/a) a<b
只需要重複這個“輾轉相減法”就可以得到最後的答案。
C++程式
版本一
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=105;
ll gcd(ll n,ll m)
{
return m==0?n:gcd(m,n%m);
}
//分數
struct F{
ll up,dw;
F(){}
F(ll a,ll b)// a/b
{
ll g=gcd(a,b);
up=a/g;
dw=b/g;
}
bool operator <(const F &fa)const// a/b<c/d 等價於 a*d<b*c
{
return up*fa.dw<dw*fa.up;
}
bool operator ==(ll x)const
{
return up==x*dw;
}
F operator /(const F &fa)
{
return F(up*fa.dw,dw*fa.up);
}
}f[N];
/*
對a1=q^x1、a2=q^x2、a3=q^x3、a4=q^x4、a5=q^x5、a6=q^x6、...
已知a1、a2、a3、a4、a5、a6、...的值,不知道q和x1、x2、x3、x4、x5、x6、...的值
求最大公比使得a1,a2,a3,a4,a5,a6,...是某個等比數列的某幾項(不一定是連續的幾項
這裡的下標不代表它們在等比數列中的位置)
易得所求的最大公比是 q^x,其中x=gcd(x1,x2,x3,x4,x5,x6,...)
這樣任何一個數都能由ans乘若干個q的得到,因此上面的數一定是等比數列的某一項
,而且這樣最大
求法:
定義Q(a,b)是由a,b唯一確定的最大比例,
那麼Q(a,b)=Q(q^x,q^y)=Q(q^x,q^(x-y))=Q(a,b/a) a<b
只需要重複這個“輾轉相減法”就可以得到最後的答案。
*/
F qgcd(F n,F m)
{
if(n<m) swap(n,m);
if(m==1)
return n;
else
return qgcd(n/m,m);
}
int main()
{
ll a[N];
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
sort(a,a+n);//排序
n=unique(a,a+n)-a;//去重
for(int i=1;i<n;i++)
{
f[i]=F(a[i],a[i-1]);
}
for(int i=2;i<n;i++)
f[1]=qgcd(f[1],f[i]);
printf("%lld/%lld\n",f[1].up,f[1].dw);
return 0;
}
版本2:參見
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=105;
//求最大公約數
ll gcd(ll n,ll m)
{
return m==0?n:gcd(m,n%m);
}
/*
n=q^i m=q^j 求q^x 其中x=gcd(i,j)
設 qgcd(q^i,q^j)=q^(gcd(i,j)) *1*
由輾轉相減求最大公約數可知,gcd(i,j)=gcd(i-j,j) i>j *2*
由1、2式可得
qgcd(n,m)=qgcd(q^i,q^j)=q^(gcd(i,j))=q^(gcd(i-j,j))=qgcd(q^(i-j),q^j)=qgcd(n/m,m)
即 qgcd(n,m)=qgcd(n/m,m)
當min(n/m,m)=1結束
*/
ll qgcd(ll n,ll m)
{
if(n<m) swap(n,m);//保證n>=m;
return m==1?n:(qgcd(n/m,m));
}
ll a[N],up[N],dw[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
sort(a,a+n);//排序
n=unique(a,a+n)-a;//去重
for(int i=1;i<n;i++) //相鄰兩項的比值 a[i]/a[i-1]
{
ll g=gcd(a[i-1],a[i]);
up[i]=a[i]/g;
dw[i]=a[i-1]/g;
}
for(int i=2;i<n;i++)
{
up[1]=qgcd(up[1],up[i]);
dw[1]=qgcd(dw[1],dw[i]);
}
printf("%lld/%lld\n",up[1],dw[1]);
return 0;
}
相關文章
- 藍橋杯__省賽__第八屆__C/C++__大學A組C++
- 藍橋杯__省賽__第九屆__C/C++__大學A組C++
- 第十五屆藍橋杯大賽軟體賽省賽 C/C++ 大學 A 組C++
- 第十三屆藍橋杯省賽A組
- 第十三屆藍橋杯省賽C/C++ B組C++
- 2015年藍橋杯六屆省賽大學B組真題
- 【藍橋杯考前突擊】第十屆藍橋杯省賽C/C++大學B組 試題 D 數的分解C++
- 第十五屆藍橋杯C++B組省賽總結C++
- 第十屆藍橋杯省賽C++B組 等差數列C++
- 2016年省賽第七屆藍橋杯B組C/C++第九題解 交換瓶子C++
- 第六屆藍橋杯省賽CC++B組C++
- 歷屆藍橋杯省賽(C、C++)的答案(轉)C++
- 第十五屆藍橋杯軟體賽省賽C/C++B 組題解C++
- 第九屆藍橋杯省賽C++A組 倍數問題(dfs)C++
- 2017省賽藍橋杯B組
- 2018藍橋杯省賽B組
- 第九屆藍橋杯B組省賽———乘積最大
- 2017第八屆藍橋杯C/C++ B組省賽第二題 秒解C++
- 試題B:小球反彈(第十五屆藍橋杯省賽B組c/c++組)C++
- 2016藍橋杯省賽第七題剪郵票
- 2013第四屆藍橋杯省賽C++A組【第一題:高斯日記】C++
- 第十一屆藍橋杯省賽CC++組第二場比賽C++
- 2013年第四屆藍橋杯省賽試題及詳解(Java本科C組)Java
- 2014年第五屆藍橋杯省賽試題及詳解(Java本科C組)Java
- 第十四屆藍橋杯省賽C++ B組(個人經歷 + 題解)C++
- 第14屆藍橋杯B組國賽
- 2018第九屆藍橋杯省賽C++B組【第四題:測試次數】C++
- 2013第四屆藍橋杯省賽C++B組【第六題:三部排序】C++排序
- 2016年藍橋杯C/C++組省賽第三題--湊算式C++
- 2016年藍橋杯C/C++組省賽第四題--快速排序C++排序
- 藍橋杯第五屆省賽題目及題解
- 第十四屆藍橋杯大賽軟體賽省賽Python 《三國遊戲》Python遊戲
- 2019年省賽第十屆藍橋杯B組C/C++試題H解 等差數列C++
- 2020藍橋杯省賽B組C++(第二場)真題C++
- 2016年藍橋杯C/C++組省賽第一題--煤球數目C++
- 2016年藍橋杯C/C++組省賽第二題--生日蠟燭C++
- 第九屆藍橋杯軟體類省賽 Java B組 題目及解析Java
- 2018年第九屆藍橋杯省賽試題及詳解(Java本科A組)Java