藍橋杯2014年第五屆決賽C_C++程式設計本科B組

MadJieJie發表於2017-04-19

1.年齡巧合

小明和他的表弟一起去看電影,有人問他們的年齡。小明說:今年是我們的幸運年啊。我出生年份的四位數字加起來剛好是我的年齡。表弟的也是如此。已知今年是2014年,並且,小明說的年齡指的是週歲。
請推斷並填寫出小明的出生年份。


2. 出棧次序

X星球特別講究秩序,所有道路都是單行線。一個甲殼蟲車隊,共16輛車,按照編號先後發車,夾在其它車流中,緩緩前行。
路邊有個死衚衕,只能容一輛車通過,是臨時的檢查站,如圖【p1.png】所示。
這裡寫圖片描述
X星球太死板,要求每輛路過的車必須進入檢查站,也可能不檢查就放行,也可能仔細檢查。
如果車輛進入檢查站和離開的次序可以任意交錯。那麼,該車隊再次上路後,可能的次序有多少種? 為了方便起見,假設檢查站可容納任意數量的汽車。
顯然,如果車隊只有1輛車,可能次序1種;2輛車可能次序2種;3輛車可能次序5種。 現在足足有16輛車啊,親!需要你計算出可能次序的數目。


遞推公式:cur=pre*(4n-2)/(n+1);

#include <stdio.h>  

int main()
{  
    long long pre=1;  
    long long cur=1;  

    for(int i=1;i<=16;i++)
    {  
        cur=pre*(4*i-2)/(i+1);  
        pre=cur;  
    }  

    printf("%lld\n",cur);  

    return 0;  
}  

3. 訊號匹配

從X星球接收了一個數字訊號序列。 現有一個已知的樣板序列。需要在訊號序列中查詢它首次出現的位置。這類似於串的匹配操作。
如果訊號序列較長,樣板序列中重複數字較多,就應當注意比較的策略了。可以仿照串的KMP演算法,進行無回溯的匹配。這種匹配方法的關鍵是構造next陣列。
next[i]表示第i項比較失配時,樣板序列向右滑動,需要重新比較的項的序號。如果為-1,表示母序列可以進入失配位置的下一個位置進行新的比較。
下面的程式碼實現了這個功能,請仔細閱讀原始碼,推斷劃線位置缺失的程式碼。

// 生成next陣列 
int* make_next(int pa[], int pn)
{
    int* next = (int*)malloc(sizeof(int)*pn);
    next[0] = -1;
    int j = 0;
    int k = -1;
    while(j < pn-1){
        if(k==-1 || pa[j]==pa[k]){
            j++;
            k++;
            next[j] = k;
        }
        else
            k = next[k];
    }

    return next;
}

// da中搜尋pa, da的長度為an, pa的長度為pn 
int find(int da[], int an, int pa[], int pn)
{
    int rst = -1;
    int* next = make_next(pa, pn);
    int i=0;  // da中的指標 
    int j=0;  // pa中的指標
    int n = 0;
    while(i<an){
        n++;
        if(da[i]==pa[j] || j==-1){
            i++;
            j++;
        }
        else
            __________________________;  //填空位置

        if(j==pn) {
            rst = i-pn;
            break;
        }
    }

    free(next);

    return rst;
}

int main()
{
    int da[] = {1,2,1,2,1,1,2,1,2,1,1,2,1,1,2,1,1,2,1,2,1,1,2,1,1,2,1,1,1,2,1,2,3};
    int pa[] = {1,2,1,1,2,1,1,1,2};

    int n = find(da, sizeof(da)/sizeof(int), pa, sizeof(pa)/sizeof(int));
    printf("%d\n", n);

    return 0;
}

answer: j=next[j]


4. 生物晶片

X博士正在研究一種生物晶片,其邏輯密集度、容量都遠遠高於普通的半導體晶片。 博士在晶片中設計了 n個微型光源,每個光源操作一次就會改變其狀態,即:點亮轉為關閉,或關閉轉為點亮。 這些光源的編號從 1 到 n,開始的時候所有光源都是關閉的。博士計劃在晶片上執行如下動作: 所有編號為2的倍數的光源操作一次,也就是把 2 4 6 8 … 等序號光源開啟
所有編號為3的倍數的光源操作一次, 也就是對 3 6 9 … 等序號光源操作,注意此時6號光源又關閉了。
所有編號為4的倍數的光源操作一次。 ….. 直到編號為 n 的倍數的光源操作一次。
X博士想知道:經過這些操作後,某個區間中的哪些光源是點亮的。
【輸入格式】 3個用空格分開的整數:N L R (L < R < N < 10^15) N表示光源數,L表示區間的左邊界,R表示區間的右邊界。
【輸出格式】 輸出1個整數,表示經過所有操作後,[L,R]區間中有多少個光源是點亮的。
例如:
輸入:
5 2 3
程式應該輸出:
2
再例如:
輸入:
10 3 6
程式應該輸出:
3


也就是從2開始,是因子就操作一次,因子數為奇數就能保證開燈了。

所以只要求得範圍內完全平方數的個數即可

int main(void)
{

    long L,R,N;  
    scanf("%ld%ld%ld",&N,&L,&R);  
    long l=(long)sqrt(L-1);  
    long r=(long)sqrt(R);  

    printf("%ld\n",R-L+1-(r-l));      

    return 0;  
}

5. Log大俠

atm參加了速算訓練班,經過刻苦修煉,對以2為底的對數算得飛快,人稱Log大俠。 一天,Log大俠的好友 drd有一些整數序列需要變換,Log大俠正好施展法力… 變換的規則是: 對其某個子序列的每個整數變為: [log_2 (x) + 1] 其中[] 表示向下取整,就是對每個數字求以2為底的對數,然後取下整。 例如對序列 3 4 2 操作一次後,這個序列會變成 2 3 2。drd需要知道,每次這樣操作後,序列的和是多少。

【輸入格式】 第一行兩個正整數 n m 。 第二行 n 個數,表示整數序列,都是正數。 接下來 m 行,每行兩個數 L R 表示 atm這次操作的是區間 [L, R],數列序號從1開始。
【輸出格式】 輸出 m 行,依次表示 atm 每做完一個操作後,整個序列的和。
例如,
輸入:
3 3
5 6 4
1 2
2 3
1 3
程式應該輸出:
10
8
6

【資料範圍】

對於 30% 的資料, n, m <= 10^3
對於 100% 的資料, n, m <= 10^5
資源約定: 峰值記憶體消耗 < 256M
CPU消耗 < 1000ms 請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。 注意: main函式需要返回0 注意: 只使用ANSI C/ANSI C++
標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。 注意: 所有依賴的函式必須明確地在原始檔中 #include ,
不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。

#include <iostream>  
using namespace std;  
int a[100005];  

int log(int n)  
{  
    int sum=1,ans=0;  
    while(sum<n)  
    {  
        sum*=2;  
        ans++;  
    }  
    if(sum==n)  
        return ans+1;  
    return ans;  

}  

int main()  
{  
    int n,m,l,r,sum=0;  
    cin>>n>>m;  
    for(int i=1; i<=n; i++)  
    {  
        cin>>a[i];  
        sum+=a[i];  
    }  
    for(int i=1; i<=m; i++)  
    {  
        cin>>l>>r;  
        for(int j=l; j<=r; j++)  
        {  
            sum-=a[j];  
            a[j]=log(a[j]);  
            sum+=a[j];  
        }  
        cout<<sum<<endl;  
    }  

    return 0;  
}  

6. 殖民地

這裡寫圖片描述

帶著殖民擴張的野心,Pear和他的星際艦隊登上X星球的某平原。為了評估這塊土地的潛在價值,Pear把它劃分成了M*N格,每個格子上用一個整數(可正可負)表示它的價值。
Pear要做的事很簡單——選擇一些格子,佔領這些土地,通過建立圍欄把它們和其它土地隔開。對於M*N的格子,一共有(M+1)N+M(N+1)條圍欄,即每個格子都有上下左右四個圍欄;不在邊界上的圍欄被相鄰的兩個格子公用。大概如下圖【p1.png】所示。
圖中,藍色的一段是圍欄,屬於格子1和2;紅色的一段是圍欄,屬於格子3和4。
每個格子有一個可正可負的收益,而建圍欄的代價則一定是正的。
你需要選擇一些格子,然後選擇一些圍欄把它們圍起來,使得所有選擇的格子和所有沒被選的格子嚴格的被隔開。選擇的格子可以不連通,也可以有“洞”,即一個連通塊中間有一些格子沒選。注意,若中間有“洞”,那麼根據定義,“洞”和連通塊也必須被隔開。
Pear的目標很明確,花最小的代價,獲得最大的收益。 【輸入資料】 輸入第一行兩個正整數M N,表示行數和列數。 接下來M行,每行N個整數,構成矩陣A,A[i,j]表示第i行第j列格子的價值。
接下來M+1行,每行N個整數,構成矩陣B,B[i,j]表示第i行第j列上方的圍欄建立代價。
特別的,B[M+1,j]表示第M行第j列下方的圍欄建立代價。
接下來M行,每行N+1個整數,構成矩陣C,C[i,j]表示第i行第j列左方的圍欄建立代價。
特別的,C[i,N+1]表示第i行第N列右方的圍欄建立代價。

【輸出資料】 一行。只有一個正整數,表示最大收益。

【輸入樣例1】 3 3 65 -6 -11 15 65 32
-8 5 66 4 1 6 7 3 11 23 21 22 5 25 22 26 1 1 13 16 3 3 4 6 3 1 2

程式應當輸出: 123

【輸入樣例2】 6 6 72 2 -7 1 43 -12 74 74 -14 35 5 3 31 71 -12 70 38 66 40 -6
8 52 3 78 50 11 62 20 -6 61 76 55 67 28 -19 68 25 4 5 8 30 5 9 20 29
20 6 18 3 19 20 11 5 15 10 3 19 23 6 24 27 8 16 10 5 22 28 14 1 5 1 24
2 13 15 17 23 28 24 11 27 16 12 13 27 19 15 21 6 21 11 5 2 3 1 11 10
20 9 8 28 1 21 9 5 7 16 20 26 2 22 5 12 30 27 16 26 9 6 23

程式應當輸出 870

【資料範圍】 對於20%的資料,M,N<=4 對於50%的資料,M,N<=15 對於100%的資料,M,N<=200
A、B、C陣列(所有的涉及到的格子、圍欄輸入資料)絕對值均不超過1000。根據題意,A陣列可正可負,B、C陣列均為正整數。

資源約定: 峰值記憶體消耗 < 256M CPU消耗 < 3000ms

請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。

所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。

注意: main函式需要返回0 注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。 注意:
所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。

提交時,注意選擇所期望的編譯器型別。


相關文章