1. 程式人生 > >牛客——2018年全國多校演算法寒假訓練營練習比賽(第一場)

牛客——2018年全國多校演算法寒假訓練營練習比賽(第一場)

這場還是新生賽,主要是模擬,搜尋,遞推遞迴,思維題。模擬手速還是慢,也會考慮不周全。

G:搜尋:

連結:https://www.nowcoder.com/acm/contest/67/G
來源:牛客網

題目描述 
    圈圈圓圓圈圈,lulu小朋友最近看喜羊羊看多了,老是受刺激就畫圓圈,聽到小於8的數字時,還會畫出十分有規律的圓圈,現在你需要根據樣例觀察出規律,編寫程式,根據輸入的數字n(n<8),輸出對應的圓圈。
輸入描述:
第一行是樣例數T(T<9)
第2到2+T-1行每行有一個整數n(n<8),代表lulu聽到的數字
輸出描述:
聽到對應數字時,輸出對應樣子的圓圈。
示例1
輸入

4
0
1
2
3
輸出

O
 O
O O
 O
    O
   O O
    O
 O     O
O O   O O
 O     O
    O
   O O
    O
             O
            O O
             O
          O     O
         O O   O O
          O     O
             O
            O O
             O
    O                 O
   O O               O O
    O                 O
 O     O           O     O
O O   O O         O O   O O
 O     O           O     O
    O                 O
   O O               O O
    O                 O
             O
            O O
             O
          O     O
         O O   O O
          O     O
             O
            O O
             O
說明

當n=0時輸出
O
當n=1時輸出
*O
O*O
*O
當n=2時輸出
****O
***O*O
****O
*O*****O
O*O***O*O
*O*****O
****O
***O*O
****O
上面的'O'是大寫英文字母O,'*'代表空格,每一行最後一個O後面不帶空格。
備註:
對於100%的資料,
0<T<9;
0<=n<8;
程式碼:
#include<bits/stdc++.h>
typedef long long LL;

using namespace std;

int len[8]={1,3,9,27,81,243,729,2187};
char a[2500][2500];
string s[2500];

void dfs(int i,int j,int n)
{
    if(n==0)
    {
        a[i][j]='O';
   // cout<<"i:"<<i<<"  "<<"j"<<j<<endl;
        return;
    }
    dfs(i,j+len[n-1],n-1);
    dfs(i+len[n-1],j,n-1);
    dfs(i+len[n-1],j+2*len[n-1],n-1);
    dfs(i+2*len[n-1],j+len[n-1],n-1);

}
int main()
{
    int t,n;
    int i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<len[n];i++){
            s[i]="";
            for(j=0;j<len[n];j++)
                a[i][j]=' ';
        }
        dfs(0,0,n);
        for(i=0;i<len[n];i++)
        {
            int cnt=len[n]-1;
            while(a[i][cnt]==' ')
                cnt--;
            for(j=0;j<=cnt;j++)
                s[i]+=a[i][j];
            cout<<s[i]<<endl;
        }
    }
    return 0;
}
H:遞推遞迴

這道題是大一時老師講過的原題。原諒我還是自己重推了一遍

連結:https://www.nowcoder.com/acm/contest/67/H
來源:牛客網

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述 
    現在有一個大小n*1的收納盒,我們手裡有無數個大小為1*1和2*1的小方塊,我們需要用這些方塊填滿收納盒,請問我們有多少種不同的方法填滿這個收納盒
輸入描述:
第一行是樣例數T
第2到2+T-1行每行有一個整數n(n<=80),描述每個樣例中的n。
輸出描述:
對於每個樣例輸出對應的方法數
示例1
輸入

3
1
2
4
輸出

1
2
5
說明

n=4,有五種方法
1:1 1 1 1
2:2 1 1
3:1 2 1
4:1 1 2
5:2 2
備註:
對於100%的資料,
0 < T < 80;
0 < n <= 80。

程式碼:
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    int n,t;
    long long a[101];
    long long b[101];
    a[1]=1;
    a[2]=2;
    a[3]=3;
    for(int i=4;i<=100;i++)
    {
        a[i]=a[i-1]+a[i-2];
    }
    while(~scanf("%d",&t))
    {
        for(int i=1;i<=t;i++)
        {
            cin>>b[i];
        cout<<a[b[i]]<<endl;
        }
    }
}

三。暴力水題

連結:https://www.nowcoder.com/acm/contest/67/I
來源:牛客網

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述 
    lulu喜歡小於等於1000的正整數,但是如果某個數是a或b的倍數,lulu會討厭這個數。如果某個數裡包含了a和b兩個數裡包含的數,lulu也會討厭。(例如a=14,b=23,如果數字中包含1、2、3、4這四個數中的任意一個數,lulu就會討厭這個數)。現在告訴你a,b,你能說出lulu喜歡的數有多少個麼。
輸入描述:
第一行是樣例數T
第2到2+T-1行每行有2個整數a b。
輸出描述:
輸出lulu喜歡的數的個數
示例1
輸入

3
2 3
14 23
1234 5678
輸出

171
190
7
說明

a=1234 b=5678的時候,只考慮含有數字9,0的數,只有7個,分別是9,99,999,90,990,909,900
備註:
對於100%的資料,
0 < T <= 20;
0 <= a <= 99999;
0 <= b <= 99999。
程式碼:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int num[11];
int like;
void chai(int a,int b)
{
    memset(num,0,sizeof(num));
    while(a>0)
    {
        int hh=a%10;
        num[hh]=1;
        a=a/10;
    }
    while(b>0)
    {
        int hh=b%10;
        num[hh]=1;
        b=b/10;
    }
}
int main()
{
    //cout<<999%10<<endl;
    int a,b;
    int t;
    while(~scanf("%d",&t))
    {
        for(int i=1;i<=t;i++)
        {
        cin>>a>>b;
        like=0;
        chai(a,b);
        for(int i=0;i<=1000;i++)
        {
            if(i%a==0||i%b==0)
            continue;
            if(i>=1&&i<10)
            {
                if(num[i]==1)
                continue;
            }
            else if(i>=10&&i<100)
            {
                if(num[i%10]==1||num[i/10]==1)
                    continue;
            }
            else if(i>=100&&i<1000)
            {
                if(num[i%10]==1)
                    continue;
                if(num[i/100]==1)
                    continue;
                if(num[(i/10)%10]==1)

                    continue;
            }
            else if(i==1000)
            {
                if(num[0]==1||num[1]==1)
                    continue;
            }
            //cout<<"i"<<i<<endl;
            like++;
        }
        cout<<like<<endl;
        }
    }
    return 0;
}
還有兩道模擬題,一直未過。。再模擬兩遍試試。

A:吃雞

這道題就是很簡單的沒有思維的模擬。

題目:

連結:https://www.nowcoder.com/acm/contest/67/A
來源:牛客網

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述 
    在絕地求生(吃雞)遊戲裡,不同的槍支有不同的威力,更是可以搭配不同的配件,以提升槍支的效能。

    每一把槍都有其威力及其可裝備配件種類。每一個配件有其所屬種類,可以為槍支提供威力的百分比加成。每一把槍只能裝備一個同類配件。給你n把槍支和m個配件,槍的威力為p,可裝備的配件數量為k,為k個不同型別的配件,同種類配件只可以裝備一個。配件種類用數字q表示,配件威力加成用一個小數b表示。請你挑選一把槍併為其搭配配件使其威力最大。
    假設一把槍的威力是p,裝配的k個配件的威力加成是bi,那麼槍最後的威力w=p*(1+b1+b2+…+bk)。


輸入描述:
資料有多組,處理到檔案結束。
第一行兩個整數n和m,代表槍支數量和配件數量。
接下來n行,描述n把槍的屬性:第一個整數為p,代表槍支的威力;第二個整數為k,代表該槍支可裝備的配件數量;後面k個整數,代表可裝備配件的種類。
接下來m行,描述m個配件的屬性:第一個整數為q,代表配件的種類,第二個浮點數為b,代表配件可以為槍支提供的威力加成。
輸出描述:
每組資料輸出為一行,輸出一個浮點數,代表合理裝備配件後的槍支最大威力。精確到小數點後4位。
示例1
輸入

3 6
120 3 1 2 3
100 4 1 2 3 4
110 3 2 3 4
1 0.12
2 0.23
2 0.26
4 0.57
3 0.35
5 0.41
輸出

239.8000
說明

對於上面的樣例,正確答案應該是,使用第三把槍,配上第三、四、五個配件。
槍的最終威力就是110*(1+0.26+0.57+0.35)=239.8
備註:
對於100%的資料,
1 <= n,m,k,q <= 1000;
0 <= p <= 1000;
0 <= b <= 1。
我的程式碼:
#include<iostream>
#include<stdio.h>
using namespace std;
double shuchu[1010];
double xpp;
struct node
{
    int p;
    int k;
    int zhonglei[1010];
}qiang[1010];
struct node1
{
  // int p;
   double b;
   int logal;
}peijian[1010];

int main()
{
    int n,m;
    int p;
    double b;
    int num=0;
    long double lala;
    long double sum;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=1000;i++)
        {
            peijian[i].logal=0;
        }
        for(int i=1;i<=n;i++)
        {
            cin>>qiang[i].p>>qiang[i].k;
            for(int j=1;j<=qiang[i].k;j++)
            {
                cin>>qiang[i].zhonglei[j];
            }
        }
        for(int i=1;i<=m;i++)
        {
          cin>>p>>b;
          if(peijian[p].logal==1)//表明這個配件之前有了
          {
              if(peijian[p].b<b)
                peijian[p].b=b;
          }
          else
          {
              peijian[p].b=b;
              peijian[p].logal=1;
          }
        }


        xpp=0;

        for(int i=1;i<=n;i++)
        {
            lala=1;
             sum=qiang[i].p;

            for(int j=1;j<=qiang[i].p;j++)
            {
               lala=lala+peijian[qiang[i].zhonglei[j]].b;
            }
            lala=lala*qiang[i].p;
           // cout<<"lala:"<<lala<<endl;
            if(lala>xpp)
                xpp=lala;
        }
       // cout<<xpp<<endl;
        printf("%.4lf\n",xpp);
        

    }
    return 0;
}
程式碼2:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k[1005],p[1005],q[1005][1005],a;
double b[1005],s,sum,ans;
  
int main()
{
    while(cin>>n>>m)
    {
        ans=0;
        memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++)
    {
        cin>>p[i]>>k[i];
        for(int j=1;j<=k[i];j++)
        cin>>q[i][j];
    }
    for(int i=1;i<=m;i++)
    {
        cin>>a>>s;
        b[a]=max(b[a],s);
          
    }
    for(int i=1;i<=n;i++)
    {
        s=1;
        for(int j=1;j<=k[i];j++)
        s+=b[q[i][j]];
        sum=p[i]*s;
        ans=max(ans,sum);
    }
    printf("%.4lf\n",ans);
    }
}
值得學習的地方是,我用的struct進行槍與配對配件的配對,程式碼2直接用二維陣列表示,而且程式碼一太繁瑣,中間判斷最大的那個時寫的也很囉嗦。這也是我寫程式碼最應該改進的地方。

F:吃雞——跑毒篇

這道題感覺就是要想透徹,一定要看樣例。將問題簡單化反而更好。

題目:

連結:https://www.nowcoder.com/acm/contest/67/F
來源:牛客網

題目描述 
    現在有一款很火的遊戲playerunknown's battlegrounds,人稱“吃雞”,在裡面經常面臨跑毒(從安全區外跑進安全區內)的問題,在安全區外,人們會處於中毒狀態,每秒會掉a%血,人們可以通過使用道具急救包把血量升回到80%,使用急救包需要原地站著6秒。現在知道在安全區外扣血速度為a%/s,角色和安全區的距離為b米,角色跑步速度為1m/s,角色有c個急救包,請問角色是否能安全跑進安全區內。(PS:角色開始的血量為100%。如果血量降到0%,立刻判定為死亡。使用急救包時,如果剛使用完畢瞬間或者正在使用急救包的時候,血量降到0%,角色立即判定為死亡。順帶一提,這裡判斷時間不存在0.xxxx秒,最小時間單位為1s)
輸入描述:
第一行是樣例數T(T<9)
第2到2+T-1行每行有三個整數a b c,其中a為安全區外的扣血速度a%/s,b為角色和安全區的距離,c為急救包的數量。
輸出描述:
如果角色能進入安全區輸出“YES”。
若角色在安全區外死亡輸出“NO”。
示例1
輸入

3
1 100 2
6 31 2
7 31 2
輸出

YES
YES
NO
說明

當a=6,b=31,c=2時,
0s起跑,10s的時候角色跑了10M,血量剩下40%,開始使用急救包,16s的時候,角色血量先降到4%再恢復到80%,然後角色繼續跑步。23s的時候,角色跑了17M,剩餘血量為38%,開始使用急救包,29s的時候,角色血量先降到2%再恢復到80%,然後角色繼續跑步。42s的時候,角色跑了30m,血量剩餘2%。當43s的時候,角色跑了31m進入了安全區內,不再扣血。
備註:
對於100%的資料,
1 <= T < 9;
0 < a <= 20;
0 < b <= 120;
0 <= c <= 8。


附上通過樣例為90.91%的程式碼以及大神的程式碼:

#include<stdio.h>
int main()
{
    int t,a,b,c,hp;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&a,&b,&c);
        hp=100;
        while(b>1)
        {
            if(hp<=7*a&&c)
            {
                hp=80;
                c--;
            }
                hp-=a;
                b--;
        }
        if(hp>0)
            printf("YES\n");
        else
            printf("NO\n");
    }
}


#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int a,b,c,c22;
        cin>>a>>b>>c;
        c22=c;
        int xueliang=100;
        int time=0;
        int jixian=6*a;
        int logal=0;
        int k=0;//表示用的急救包的次數
        while(1)
        {
            if(b<=1)
                break;
            if(c==0)
            {
                if(c22!=0)
                {
                    if(time+80/a>b-1)
                    logal==0;
                    else
                    logal=1;
                  
                    break;
                }
                else if(c22==0)
                {
                    if(time+100/a>b-1)
                    logal==0;
                    else
                    logal=1;
                    break;
                }
            }
            xueliang=xueliang-a;
            time++;//過了一秒鐘,走了1米
            if(time>=b)
            {
                break;
            }
            if(xueliang-jixian<a)
            {
                c--;
                if(c<0)
                {
                    logal=1;
                    break;
                }
                xueliang=80;
                continue;
            }
        }
        if(logal==1)
            cout<<"NO"<<endl;
        else
            cout<<"YES"<<endl;
    }
    return 0;
}
程式碼簡潔是我要追求的。