2016年藍橋杯省賽C/C++ A組題解(含題目)
1. 網友年齡
某君新認識一網友。 當問及年齡時,他的網友說: “我的年齡是個2位數,我比兒子大27歲, 如果把我的年齡的兩位數字交換位置,剛好就是我兒子的年齡”
請你計算:網友的年齡一共有多少種可能情況?
提示:30歲就是其中一種可能哦. 請填寫表示可能情況的種數。
注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
小學奧數或者列舉一下:7
2. 生日蠟燭
某君從某年開始每年都舉辦一次生日party,並且每次都要吹熄與年齡相同根數的蠟燭。 現在算起來,他一共吹熄了236根蠟燭。
請問,他從多少歲開始過生日party的?
請填寫他開始過生日party的年齡數。
注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
等差數列,列舉首項:
#include <bits/stdc++.h>
using namespace std;
int main()
{
for (int i=1;i<=100;i++) {
int sum=0,j=i;
while (sum<236) {
sum+=j++;
}
if (sum==236) {
printf("%d %d\n",i,j);
}
}
return 0;
}
我覺得列舉首項從1到100是比較合理的。。。有人說答案是236我覺得他可能沒救了...
正確答案:
26
3. 方格填數
如下的10個格子
填入0~9的數字。要求:連續的兩個數字不能相鄰。 (左右、上下、對角都算相鄰)
一共有多少種可能的填數方案?
請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
dfs,不過不優化的話有
#include <bits/stdc++.h>
using namespace std;
/*本來要判斷八個格子,
*但是由於是從左往右從上往下填的,
*只要判斷左、左上、上、右上
*/
const int dx[]={0,-1 ,-1,-1};
const int dy[]={-1,-1,0,1};
const int INF=1e9;
bool used[10];
int ans=0;
int a[5][5];
bool alright(int n,int x,int y)
{
for (int i=0;i<4;i++) {
int xx=x+dx[i],yy=y+dy[i];
if (xx<1||yy<1||xx>3||yy>4) continue;
if (abs(n-a[xx][yy])==1) return false;
}
return true;
}
void dfs(int x,int y)
{
if (x==3&&y==4) {
ans++;
return;
}
for (int i=0;i<=9;i++) {
if (!used[i]&&alright(i,x,y)) {
a[x][y]=i;
used[i]=true;
if (y==4) dfs(x+1,1);
else dfs(x,y+1);
used[i]=false;
a[x][y]=-INF;
}
}
}
int main()
{
for (int i=1;i<=3;i++) {
for (int j=1;j<=4;j++) {
a[i][j]=-INF;
}
}
dfs(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;
}
注意:只填寫缺少的內容,不要書寫任何題面已有程式碼或說明性文字。
要做這道題首先要知道位運算,位運算資料
最好還要知道負數怎麼參與位運算,補碼資料
如果想要了解我的做法還要學習lowbit,lowbit資料
這題當時我想了很久,因為它必須在一行內就算出來,所以我想到了lowbit,它可以很方便的得到。
然而怎麼讓它套用上lowbit也不是一件容易的事。。。不過最後還是做出來了~
要消除x末尾所有的1,可以先把x加上1:
00000000000000000000000001100111 + 1 =
00000000000000000000000001101000
再減去新的數的lowbit:
00000000000000000000000001101000 - 00000000000000000000000000001000 =
00000000000000000000000001100000
所以我的答案是:x+1-((x+1)&(-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一個一個填,每個等式判斷一下。
#include <bits/stdc++.h>
using namespace std;
bool used[15];
int a[15];
int ans=0;
void dfs(int dep)
{
if (dep==13) {
//必須整除,變成乘法判斷
if (a[10]==a[11]*a[12]) ans++;
return;
}
if (dep==10) {
if (a[7]*a[8]!=a[9]) return;
}
if (dep==7) {
if (a[4]-a[5]!=a[6]) return;
}
if (dep==4) {
if (a[1]+a[2]!=a[3]) return;
}
for (int i=1;i<=13;i++) {
if (!used[i]) {
used[i]=true;
a[dep]=i;
dfs(dep+1);
a[dep]=-1;
used[i]=false;
}
}
}
int main()
{
dfs(1);
printf("%d\n",ans);
return 0;
}
答案:64
詳見PPT。
7. 剪郵票
如【圖1.jpg】, 有12張連在一起的12生肖的郵票。
現在你要從中剪下5張來,要求必須是連著的。 (僅僅連線一個角不算相連)
比如,【圖2.jpg】,【圖3.jpg】中,粉紅色所示部分就是合格的剪取。
原諒我好像又講錯了。。。看來去年掛的就是這題。。。
這題不能直接按方向dfs。。。因為按方向的dfs實際上只是一筆畫。。。
不過我們可以用dfs選出5個格子然後算一個連通塊的大小看是不是等於5。
#include <bits/stdc++.h>
using namespace std;
int va[6][6],cor[13][2],q[6];
int ans=0;
int getsum(int x,int y)
{
//值為0的不用計算
if (va[x][y]==0) return 0;
//算過一次就要清零,避免重複
va[x][y]=0;
//超出範圍也沒事,因為va陣列的周圍都是0
return 1+getsum(x-1,y)+getsum(x+1,y)+getsum(x,y-1)+getsum(x,y+1);
}
void dfs(int dep,int last) {
if (dep==5) {
memset(va,0,sizeof(va));
for (int i=0;i<5;i++) {
va[cor[q[i]][0]][cor[q[i]][1]]=1;
}
if (getsum(cor[last][0],cor[last][1])==5) ans++;
return;
}
for (int i=last+1;i<=12;i++) {
//q陣列儲存我們選中的格子
q[dep]=i;
dfs(dep+1,i);
q[dep]=-1;
}
}
int main()
{
//算出第n個格子的橫縱座標
for (int i=1,n=1;i<=3;i++) {
for (int j=1;j<=4;j++,n++) {
cor[n][0]=i;cor[n][1]=j;
}
}
dfs(0,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 , 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
時間3s,直接列舉。
#include <bits/stdc++.h>
using namespace std;
void resolve(int n)
{
int n1=n;
for (int i=0;i<=sqrt(n1);i++) {
int n2=n1-i*i;
for (int j=0;j<=sqrt(n2);j++) {
int n3=n2-j*j;
for (int k=0;k<=sqrt(n3);k++) {
int n4=n3-k*k;
int l=sqrt(n4);
if (l*l==n4) {
printf("%d %d %d %d\n",i,j,k,l);
return;
}
}
}
}
}
int main()
{
int n;
scanf("%d",&n);
resolve(n);
return 0;
}
9. 密碼脫落
X星球的考古學家發現了一批古代留下來的密碼。
這些密碼是由A、B、C、D 四種植物的種子串成的序列。
仔細分析發現,這些密碼串當初應該是前後對稱的(也就是我們說的映象串)。
由於年代久遠,其中許多種子脫落了,因而可能會失去映象的特徵。你的任務是: 給定一個現在看到的密碼串,計算一下從當初的狀態,它要至少脫落多少個種子,才可能會變成現在的樣子。
輸入一行,表示現在看到的密碼串(長度不大於1000)
要求輸出一個正整數,表示至少脫落了多少個種子。例如,輸入:
ABCBA
則程式應該輸出:
0
再例如,輸入:
ABECDCBABC
則程式應該輸出:
3資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 1000ms請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。 注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
經典水題,不過可能要先了解一下動態規劃 動態規劃資料
教材原題 最小回文代價資料 看前兩頁就可以了,教材的具體實現都是複雜化的。
原串和逆序串做LCS LCS資料
#include <bits/stdc++.h>
using namespace std;
char s[1010];
int dp[1010][1010];
int main()
{
scanf("%s",s+1);
int n=strlen(s+1);
for (int i=1;i<=n;i++) {
for (int j=1;j<=n;j++) {
if (s[i]==s[n+1-j]) {
dp[i][j]=dp[i-1][j-1]+1;
} else {
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
printf("%d\n",n-dp[n][n]);
return 0;
}
10. 最大比例
以上各題的解法和答案,如有錯誤,請及時指出,謝謝!