2014年第五屆藍橋杯C/C++B組省賽題目解析


一、啤酒和飲料

啤酒每罐2.3元,飲料每罐1.9元。小明買了若干啤酒和飲料,一共花了82.3元。

我們還知道他買的啤酒比飲料的數量少,請你計算他買了幾罐啤酒。

注意:答案是一個整數。請通過瀏覽器提交答案。

不要書寫任何多余的內容(例如:寫了飲料的數量,添加說明文字等)。

 

分析:此題可用循環暴力求解出結果。

數值先都擴大十倍,方便計算。

全部啤酒罐數:823/23=35.78;全部飲料罐數:823/19=43.31;啤酒和飲料對半罐數:823/42=19.59

設啤酒x,飲料y,則根據上述計算可知,x<y,20<=y<=43

#include<stdio.h>
#include <cstdio>
#include <cmath>
using namespace std;

int main(){
    
    for(int x = 1;x < 19;x++){
        for(int y = 19;y <= 43;y++){
            if(fabs(23*x + 19*y - 823) <= 1e-3 && x<y)  
            {
                printf("%d %d\n",x,y);  //輸出啤酒與飲料的罐數 
            }
        }
    }    
    return 0;
} 

 

答案:11.

 

二、切面條

一根高筋拉面,中間切一刀,可以得到2根面條。

如果先對折1次,中間切一刀,可以得到3根面條。

如果連續對折2次,中間切一刀,可以得到5根面條。

那么,連續對折10次,中間切一刀,會得到多少面條呢?

答案是個整數,請通過瀏覽器提交答案。不要填寫任何多余的內容。

 

分析:觀察得到的面條數,發現規律 f[n]=2*f[n-1]-1。因此我們可以通過循環計算出答案

#include <stdio.h>
long f[12];
int main(){
    f[0]=2;
    for(int i = 1;i <= 10;i++){
        f[i] = 2*f[i-1] - 1;
    }
    printf("%ld\n",f[10]);
}

 

答案:1025.

 

三、李白打酒

話說大詩人李白,一生好飲。幸好他從不開車。

一天,他提着酒壺,從家里出來,酒壺中有酒2斗。他邊走邊唱:

無事街上走,提壺去打酒。
逢店加一倍,遇花喝一斗。

這一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了

請你計算李白遇到店和花的次序,可以把遇店記為a,遇花記為b。則:babaabbabbabbbb 就是合理的次序。像這樣的答案一共有多少呢?請你計算出所有可能方案的個數(包含題目給出的)。

注意:通過瀏覽器提交答案。答案是個整數。不要書寫任何多余的內容。

 

分析1:全排列,循環判斷。參考資料 next_permutation

#include <stdio.h>
#include <algorithm>
using namespace std;
int f[16]; 
int main(){
    int i,j,tot=0;
    for(i = 0;i < 5;i++)
        f[i] = 0;
    for(;i < 15;i++){
        f[i] = 1;
    }    
    do{
        int ans=2;
        bool error=false;
        for(j = 0;j < 15;j++){
            if(f[j] == 0)
                ans *= 2;
            else if(f[j] == 1)
                ans -= 1;
            if(ans < 0){
                error = true;
                break;    
            } 
        }
        if(error) continue;
        if(ans==0){
            tot++;
        }
        
    }while(next_permutation(f,f+14));  //求數列的全排列 
    
    printf("%d\n",tot);
    return 0;
}

 

分析2:運用DFS算法,當遇見店時酒乘一倍,遇見花時酒減1,直到店和花都為0時,輸出酒的數值。

#include <stdio.h>
int tot=0;
void dfs(int dian,int hua,int jiu){
    if(dian==0 && hua==0 && jiu==1){
        tot++;
        return ;
    } 
    if(dian > 0)
        dfs(dian-1,hua,jiu*2);
    if(jiu>0 && hua>0)
        dfs(dian,hua-1,jiu-1);
}

int main(){
    int n;    
    dfs(5,9,2);
    printf("%d\n",tot);
    
    return 0;
} 

 

答案:14

 

四、史豐收速算

史豐收速算法的革命性貢獻是:從高位算起,預測進位。不需要九九表,徹底顛覆了傳統手算!

速算的核心基礎是:1位數乘以多位數的乘法。

其中,乘以7是最復雜的,就以它為例。

因為,1/7 是個循環小數:0.142857...,如果多位數超過 142857...,就要進1

同理,2/7, 3/7, ... 6/7 也都是類似的循環小數,多位數超過 n/7,就要進n

下面的程序模擬了史豐收速算法中乘以7的運算過程。

乘以 7 的個位規律是:偶數乘以2,奇數乘以2再加5,都只取個位。

乘以 7 的進位規律是:
滿 142857... 進1,
滿 285714... 進2,
滿 428571... 進3,
滿 571428... 進4,
滿 714285... 進5,
滿 857142... 進6

請分析程序流程,填寫划線部分缺少的代碼。

//計算個位 
int ge_wei(int a)
{
    if(a % 2 == 0)
        return (a * 2) % 10;
    else
        return (a * 2 + 5) % 10;    
}

//計算進位 
int jin_wei(char* p)
{
    char* level[] = {
        "142857",
        "285714",
        "428571",
        "571428",
        "714285",
        "857142"
    };
    
    char buf[7];
    buf[6] = '\0';
    strncpy(buf,p,6);
    
    int i;
    for(i=5; i>=0; i--){
        int r = strcmp(level[i], buf);
        if(r<0) return i+1;
        while(r==0){
            p += 6;
            strncpy(buf,p,6);
            r = strcmp(level[i], buf);
            if(r<0) return i+1;
            ______________________________;  //填空
        }
    }
    
    return 0;
}

//多位數乘以7
void f(char* s) 
{
    int head = jin_wei(s);
    if(head > 0) printf("%d", head);
    
    char* p = s;
    while(*p){
        int a = (*p-'0');
        int x = (ge_wei(a) + jin_wei(p+1)) % 10;
        printf("%d",x);
        p++;
    }
    
    printf("\n");
}

int main()
{
    f("428571428571");
    f("34553834937543");        
    return 0;
}

 

#include <cstring>
#include <cstdio>
using namespace std;


//計算個位 
int ge_wei(int a)
{
    if(a % 2 == 0)
        return (a * 2) % 10;
    else
        return (a * 2 + 5) % 10;    
}

//計算進位 
int jin_wei(char* p)
{
    char* level[] = {
        "142857",
        "285714",
        "428571",
        "571428",
        "714285",
        "857142"
    };
    
    char buf[7];
    buf[6] = '\0';
    strncpy(buf,p,6);
    
    int i;
    for(i=5; i>=0; i--){
        int r = strcmp(level[i], buf);
        if(r<0) return i+1;
        while(r==0){
            p += 6;
            strncpy(buf,p,6);
            r = strcmp(level[i], buf);
            if(r<0) return i+1;
            if(r>0) return i;  //填空
        }
    }
    
    return 0;
}

//多位數乘以7
void f(char* s) 
{
    int head = jin_wei(s);
    if(head > 0) printf("%d", head);
    
    char* p = s;
    while(*p){
        int a = (*p-'0');
        int x = (ge_wei(a) + jin_wei(p+1)) % 10;
        printf("%d",x);
        p++;
    }
    
    printf("\n");
}

int main()
{
    f("428571428571");
    f("34553834937543");        
    return 0;
}
完整代碼

 

答案:if(r>0) return i;

 

五、打印圖形

小明在X星球的城堡中發現了如下圖形和文字:
rank=3

rank=5

ran=6

小明開動腦筋,編寫了如下的程序,實現該圖形的打印。

#define N 70

void f(char a[][N], int rank, int row, int col)
{
    if(rank==1){
        a[row][col] = '*';
        return;
    }
    
    int w = 1;
    int i;
    for(i=0; i<rank-1; i++) w *= 2;
    
    ____________________________________________;
    f(a, rank-1, row+w/2, col);
    f(a, rank-1, row+w/2, col+w);
}

int main()
{
    char a[N][N];
    int i,j;
    for(i=0;i<N;i++)
    for(j=0;j<N;j++) a[i][j] = ' ';
    
    f(a,6,0,0);
    
    for(i=0; i<N; i++){
        for(j=0; j<N; j++) printf("%c",a[i][j]);
        printf("\n");
    }
    
    return 0;
}

 

#include <stdio.h>
#define N 70

void f(char a[][N], int rank, int row, int col)
{
    if(rank==1){
        a[row][col] = '*';
        return;
    }
    
    int w = 1;
    int i;
    for(i=0; i<rank-1; i++) w *= 2;
    
    f(a, rank-1, row, col+w/2);                            //填空 
    f(a, rank-1, row+w/2, col);
    f(a, rank-1, row+w/2, col+w);
}

int main()
{
    char a[N][N];
    int i,j;
    for(i=0;i<N;i++)
    for(j=0;j<N;j++) a[i][j] = ' ';
    
    f(a,6,0,0);
    
    for(i=0; i<N; i++){
        for(j=0; j<N; j++) printf("%c",a[i][j]);
        printf("\n");
    }
    
    return 0;
}
完整代碼

 

答案:f(a, rank-1, row, col+w/2);

 

六、奇怪的分式

上小學的時候,小明經常自己發明新算法。一次,老師出的題目是:

1/4 乘以 8/5

小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (參見圖1.png)

老師剛想批評他,轉念一想,這個答案湊巧也對啊,真是見鬼!

對於分子、分母都是 1~9 中的一位數的情況,還有哪些算式可以這樣計算呢?

請寫出所有不同算式的個數(包括題中舉例的)。

顯然,交換分子分母后,例如:4/1 乘以 5/8 是滿足要求的,這算做不同的算式。

但對於分子分母相同的情況,2/2 乘以 3/3 這樣的類型太多了,不在計數之列!

注意:答案是個整數(考慮對稱性,肯定是偶數)。請通過瀏覽器提交。不要書寫多余的內容。

 

分析:先試着簡單模擬,然后暴力破解法求出答案。

#include <stdio.h>
#include <cstring>
using namespace std;

int main(){
    int tot=0;
    for(int a=1;a<=9;a++){
        for(int b=1;b<=9;b++){
            for(int c=1;c<=9;c++){
                for(int d=1;d<=9;d++){
                    if(a!=b && c!=d){
                        if(a*c*(b*10+d) == b*d*(a*10+c))
                            {
                                tot++;
                                printf("%d/%d * %d/%d= %d/%d\n",a,b,c,d,a*10+c,b*10+d);
                            }
                    }
            
                }
            }
        }
    }
    printf("tot=%d\n",tot);
    
    return 0;
}

 

答案:14.

 

七、六角填數

如圖所示六角形中,填入1~12的數字。

使得每條直線上的數字之和都相同。

圖中,已經替你填好了3個數字,請你計算星號位置所代表的數字是多少?

請通過瀏覽器提交答案,不要填寫多余的內容。

分析:暴力求解。

#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

int f[13];  //儲存十二個數字 
int x[6];  //共六條線 
int main(){
    int k=0;
    for(int i=2;i<=12;i++){
        if(i!=3 && i!=8) f[k++]=i;
    }
    
    do{
        bool error =false;
        int m,n;
        x[0]=8+f[0]+f[7]+3;
        x[1]=f[8]+1+f[0]+f[1];
        x[2]=8+f[1]+f[2]+f[3];
        x[3]=1+f[2]+f[4]+f[5];
        x[4]=3+f[3]+f[4]+f[6];
        x[5]=f[5]+f[6]+f[7]+f[8]; 
        
        for(m=0;m<=4;m++){
            for(n=m+1;n<=5;n++){
                if(x[m] != x[n]){
                error=true;
                    break;    
                }
            }
            if(error) break;
        }
        
        if(m==5 && n==6 && error==false) 
            for(int k=0;k<=9;k++)
                printf("%d ",f[k]);
        
    }while(next_permutation(f,f+9));
        for(int i=2;i<=12;i++){
        if(i!=3&&i!=8) f[k++]=i;
    }
    
    return 0;
}

 

答案:10

 

八、螞蟻感冒

長100厘米的細長直桿子上有n只螞蟻。它們的頭有的朝左,有的朝右。

每只螞蟻都只能沿着桿子向前爬,速度是1厘米/秒。

當兩只螞蟻碰面時,它們會同時掉頭往相反的方向爬行。

這些螞蟻中,有1只螞蟻感冒了。並且在和其它螞蟻碰面時,會把感冒傳染給碰到的螞蟻。

請你計算,當所有螞蟻都爬離桿子時,有多少只螞蟻患上了感冒。

【數據格式】

第一行輸入一個整數n (1 < n < 50), 表示螞蟻的總數。

接着的一行是n個用空格分開的整數 Xi (-100 < Xi < 100), Xi的絕對值,表示螞蟻離開桿子左邊端點的距離。正值表示頭朝右,負值表示頭朝左,數據中不會出現0值,也不會出現兩只螞蟻占用同一位置。其中,第一個數據代表的螞蟻感冒了。

要求輸出1個整數,表示最后感冒螞蟻的數目。

例如,輸入:
3
5 -2 8
程序應輸出:
1

再例如,輸入:
5
-10 8 -20 12 25
程序應輸出:
3

資源約定:
峰值內存消耗 < 256M
CPU消耗 < 1000ms

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

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

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

 

思路:

  1. 首先一定要記住螞蟻都具有相同的速度,所以他們的相對位置不會變
  2. 我們可以從第一只那只感冒的螞蟻入手,實際上,如果第一只螞蟻向右爬,則它出發的位置右邊的螞蟻中向左爬且離第一只螞蟻最近的那只會被傳染,然后雙方會掉頭爬行。
  3. 接下來,第一只螞蟻左邊的螞蟻中向右爬行且離第一只螞蟻最近的那只會被傳染,雙方再掉頭。而對於一開始第一只被傳染的那只螞蟻來說,它會傳染給他右邊向左爬且最近的螞蟻……
 所以,將問題簡化,實際上就是 向右爬的第一只感冒螞蟻會先傳染它右邊所有向左爬的螞蟻,掉頭向左爬時會傳染給左邊所有向右爬的螞蟻
 同理,若第一只螞蟻開始時是向左爬,被傳染的螞蟻=左邊所有向右爬的螞蟻+右邊所有向左爬的螞蟻。
 注意這種思想需要有個第一只感冒的螞蟻是否會掉頭的判斷,因為第一只螞蟻向左(或右)爬的時候,若不會遇到一只迎面而來的螞蟻使它掉頭的話,則即使右邊有向左爬的螞蟻,也不會被其傳染。
#include<stdio.h>  
#include<string.h>  
struct Node  
{  
    int pos,dir;  
} Node[55];  

int main()  
{  
    int n,ans=1;  
    scanf("%d",&n);  
    memset(Node,0,sizeof(Node));  
    for(int i=0; i<n; i++)  
    {  
        scanf("%d",&Node[i].pos);  
        if(Node[i].pos>0)   
            Node[i].dir=1;   
        else  
        {  
            Node[i].dir=-1;  
            Node[i].pos*=-1;  //在此強調:正負僅僅表示方向,位置是其絕對值  
        }  
    }  
    int turn=0;  //考慮到第一只感冒的螞蟻可能不會掉頭的情況,設置標記turn,初始化為0  
    if(Node[0].dir==1)  
    {  
        for(int i=1; i<n; i++)  
        {  
            if((Node[i].pos>Node[0].pos) && (Node[i].dir==-1))  
            {  
                turn=1;//第一只感冒的螞蟻遇到迎面而來的螞蟻,它將掉頭,將turn標記為1  
                ans++;  
            }  
        }  
        for(int i=1; i<n; i++)  
        {  
            if((Node[i].pos<Node[0].pos) && (Node[i].dir==1) && turn)//只有第一只螞蟻掉頭了,才會與另一方向前進的螞蟻出現碰頭的情形,因此注意加上turn是否為1的判斷  
                ans++;  
        }  
    }  
    else  
    {  
        for(int i=1; i<n; i++)  
        {  
            if((Node[i].pos<Node[0].pos) && (Node[i].dir==1))  
            {  
                turn=1;  
                ans++;  
            }  
        }  
        for(int i=1; i<n; i++)  
        {  
            if((Node[i].pos>Node[0].pos) && (Node[i].dir==-1) && turn)  
                ans++;  
        }  
    }  
    printf("%d\n",ans);  
    return 0;  
}

 

#include <stdio.h>
struct mayi
{
    int direct;  //0為左,1為右 
    int dist;   //距離左端點距離 
    int cold;  //0為正常,1為感冒     
} ;

int main()
{
    int n,i,sign,j,num=0;
    scanf("%d",&n);
    struct mayi a[n];
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i].dist);
        a[i].dist*=2;
        a[i].direct=1;
        a[i].cold=0;
        if(a[i].dist<0) 
        {
            a[i].dist*=-1;
            a[i].direct=0;    
        }    
        a[0].cold=1;    
    } 

    for(;;)
       {
           sign=0;
         for(i=0;i<n;i++)  //所有螞蟻走路 
           {
               if(a[i].direct==0) a[i].dist--;
               else a[i].dist++;
           } 
   
           for(i=0;i<n-1;i++)
              for(j=i+1;j<n;j++)
           {
            if(a[i].dist==a[j].dist)
            {
                if(a[i].direct==0) 
                    {a[i].direct=1;}
                else 
                    a[i].direct=0;
            
            if(a[j].direct==0)
            {a[j].direct=1;}
            else a[j].direct=0;
            if(a[i].cold==1 ) a[j].cold=1; 
            if(a[j].cold==1 ) a[i].cold=1; 
              }
        }
   
        for(i=0;i<n;i++)
          {
                 if(a[i].dist>=0 && a[i].dist<=200)
                  {
                   sign=1;
                   break;
             }
           }    
        if(sign==0) break;
    }
        for(i=0;i<n;i++)
            if(a[i].cold==1) 
                num++;
    printf("%d\n",num);

    return 0;
} 
參考代碼2

 

九、地宮取寶

X 國王有一個地宮寶庫。是 n x m 個格子的矩陣。每個格子放一件寶貝。每個寶貝貼着價值標簽。

地宮的入口在左上角,出口在右下角。

小明被帶到地宮的入口,國王要求他只能向右或向下行走。

走過某個格子時,如果那個格子中的寶貝價值比小明手中任意寶貝價值都大,小明就可以拿起它(當然,也可以不拿)。

當小明走到出口時,如果他手中的寶貝恰好是k件,則這些寶貝就可以送給小明。

請你幫小明算一算,在給定的局面下,他有多少種不同的行動方案能獲得這k件寶貝。

【數據格式】

輸入一行3個整數,用空格分開:n m k (1<=n,m<=50, 1<=k<=12)

接下來有 n 行數據,每行有 m 個整數 Ci (0<=Ci<=12)代表這個格子上的寶物的價值

要求輸出一個整數,表示正好取k個寶貝的行動方案數。該數字可能很大,輸出它對 1000000007 取模的結果。

例如,輸入:
2 2 2
1 2
2 1
程序應該輸出:
2

再例如,輸入:
2 3 2
1 2 3
2 1 5
程序應該輸出:
14

資源約定:
峰值內存消耗 < 256M
CPU消耗 < 1000ms

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

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

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

 

解法1,DFS搜索

#include<stdio.h>
long long ans;
int n,m,k;
int a[55][55];
const int INF=0x3f3f3f3f;
void dfs(int x,int y,int pre,int max)
{
    if(pre>k)
        return ;
    if(x==n-1 && y==m-1)
    {
        if(pre==k||(pre==k-1&&max<a[x][y]))  //走到終點時剛好拿到了K件禮物或者拿到了k-1件禮物,在該點的禮物的價值又大於之前拿到的最大價值。此時方案數加一。
            ans++;
        return ;
    }
    if(x < n-1)//向下走
    {
        if(a[x][y]>max)
            dfs(x+1,y,pre+1,a[x][y]);
        dfs(x+1,y,pre,max);
    }
    if(y < m-1)//向右走
    {
        if(a[x][y]>max)
            dfs(x,y+1,pre+1,a[x][y]);
        dfs(x,y+1,pre,max);
    }
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&k))  //循環從輸入流讀取m、n、k,直到遇到EOF為止,等同於 while (scanf("%d%d",&m,&n)!=EOF) 
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                scanf("%d",&a[i][j]);
        ans=0;
        dfs(0,0,0,-INF);
        printf("%lld\n",ans%1000000007);
    }
    return 0;
}

 

解法2,記憶化搜索

#include<stdio.h>  
#include<string.h>  
int n,m,k;  
int a[55][55][15][15];  
int map[55][55];  
int dfs(int x,int y,int pre,int max)  
{  
    if(a[x][y][pre][max+1]>=0)  
        return a[x][y][pre][max+1];  
    int sum=0;  
    if(x==n-1&&y==m-1)  
    {  
        if(pre==k||(pre==k-1&&max<map[x][y]))  
        {  
            sum++;  
            sum%=1000000007;  
        }  
        a[x][y][pre][max+1]=sum;  
        return a[x][y][pre][max+1];  
    }  
    if(x<n-1)  
    {  
        if(map[x][y]>max)  
            sum+=dfs(x+1,y,pre+1,map[x][y]);  
        sum+=dfs(x+1,y,pre,max);  
        sum%=1000000007;  
    }  
    if(y<m-1)  
    {  
        if(map[x][y]>max)  
            sum+=dfs(x,y+1,pre+1,map[x][y]);  
        sum+=dfs(x,y+1,pre,max);  
        sum%=1000000007;  
    }  
    a[x][y][pre][max+1]=sum%1000000007;  
    return a[x][y][pre][max+1];  
}  

int main()  
{  
    while(~scanf("%d%d%d",&n,&m,&k))  //循環從輸入流讀取m、n、k,直到遇到EOF為止,等同於 while (scanf("%d%d",&m,&n)!=EOF)
    {  
        memset(a,-1,sizeof(a));  
        for(int i=0; i<n; i++)  
            for(int j=0; j<m; j++)  
                scanf("%d",&map[i][j]);  
        dfs(0,0,0,-1);  
        printf("%lld\n",a[0][0][0][0]%1000000007);  
    }  
    return 0;  
}

 

#include<stdio.h>
#include<string.h>
#define N 55
#define MOD  1000000007

int map[55][55];
int dp[55][55][15][15];

int main(void)
{
    int n, m, k;
    int i, j, c, val, aMax;
    scanf("%d%d%d", &n, &m, &k);
    aMax = 0;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= m; j++)
        {
            scanf("%d", &map[i][j]);
//            map[i][j]++;
            if(aMax < map[i][j])
            {
                aMax = map[i][j];
            }
        }
    }
    memset(dp, 0, sizeof(dp));
    dp[1][1][0][0] = 1;
    dp[1][1][1][map[1][1]] = 1;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= m; j++)
        {
            dp[i][j][0][0] += dp[i][j - 1][0][0] + dp[i - 1][j][0][0];
            dp[i][j][0][0] %= MOD;
            for(c = 1; c <= k; c++)
            {
                for(val = 0; val <= aMax; val++)
                {
                    dp[i][j][c][val] += dp[i][j - 1][c][val] + dp[i - 1][j][c][val];
                    dp[i][j][c][val] %= MOD;
                }
                if(c == 1)
                {
                    dp[i][j][1][map[i][j]] += dp[i][j - 1][0][0];
                    dp[i][j][1][map[i][j]] %= MOD;
                    dp[i][j][1][map[i][j]] += dp[i - 1][j][0][0];
                    dp[i][j][1][map[i][j]] %= MOD;
                }
                else
                {
                    for(val = 0; val < map[i][j]; val++)
                    {
                        dp[i][j][c][map[i][j]] += dp[i][j - 1][c - 1][val];
                        dp[i][j][c][map[i][j]] %= MOD;
                        dp[i][j][c][map[i][j]] += dp[i - 1][j][c - 1][val];
                        dp[i][j][c][map[i][j]] %= MOD;
                    }
                }
            }
        }
    }
    
    int sum = 0;
    for(i = 0; i <= aMax; i++)
    {
        sum += dp[n][m][k][i];
        sum %= MOD;
    }
    printf("%d", sum);
    return 0;
}
參考代碼3(map、dp)

 

十、小朋友排隊

n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。

每個小朋友都有一個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。

如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2(即不高興程度為3),依次類推。當要求某個小朋友第k次交換時,他的不高興程度增加k。

請問,要讓所有小朋友按從低到高排隊,他們的不高興程度之和最小是多少。

如果有兩個小朋友身高一樣,則他們誰站在誰前面是沒有關系的。

【數據格式】

輸入的第一行包含一個整數n,表示小朋友的個數。
第二行包含 n 個整數 H1 H2 … Hn,分別表示每個小朋友的身高。
輸出一行,包含一個整數,表示小朋友的不高興程度和的最小值。

例如,輸入:
3
3 2 1
程序應該輸出:
9

【樣例說明】
首先交換身高為3和2的小朋友,再交換身高為3和1的小朋友,再交換身高為2和1的小朋友,每個小朋友的不高興程度都是3,總和為9。


【數據規模與約定】
對於10%的數據, 1<=n<=10;
對於30%的數據, 1<=n<=1000;
對於50%的數據, 1<=n<=10000;
對於100%的數據,1<=n<=100000,0<=Hi<=1000000。


資源約定:
峰值內存消耗 < 256M
CPU消耗 < 1000ms


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

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

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

 

#include<stdio.h>
int h[100100];
int un[100100];
int b[1000100];
int reb[1000100];

int Lowbit(int x){
    return x&(x^(x-1));
}

int sum(int bit[], int idx){
    int ret = 0;
    while(idx > 0){
        ret += bit[idx];
        idx -= Lowbit(idx);
    }
    return ret;
}

void add(int bit[], int idx, int val){
    while(idx < 1000100){
        bit[idx] += val;
        idx += Lowbit(idx);
    }
}

long long uVal[100100];
int main(void){
    int n, i;
    scanf("%d", &n);
    uVal[0] = 0;
    for(i = 0; i < n; i++){
        scanf("%d", &h[i]);
        h[i]++;
        uVal[i + 1] = uVal[i] + i + 1;
        
        un[i] += i - sum(b, h[i]);
        add(b, h[i], 1);
    }
    long long ans = 0;
    for(i = n - 1; i >= 0; i--){
        un[i] += sum(reb, h[i] - 1);
        add(reb, h[i], 1);
        
        ans += uVal[un[i]];
    }
    printf("%I64d\n", ans);
    
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM