SCNUOJ 2020 軟件學院 天梯賽選拔賽 + 藍橋杯熱身賽 題解

SCNUOJ 2020 軟院天梯賽選拔賽 + 藍橋杯熱身賽 題解


寫在前面

本次比賽面向軟件學院2017、2018铐懊、2019級學生邀桑,賽制為IOI賽制,時長3小時科乎。

最終共有311名同學提交代碼概漱,共有302名同學獲得有效分數(shù)。

最終前18名的同學(除去打星)入圍2020軟件學院團體程序設計天梯賽名單喜喂,其中最高分為183分瓤摧,最低分為105分。

祝賀他們玉吁!

題目限制

題目 時間限制 空間限制
L1-1 400MS 64MB
L1-2 400MS 64MB
L1-3 1000MS 256MB
L1-4 1000MS 64MB
L1-5 1000MS 64MB
L1-6 1000MS 64MB
L1-7 1000MS 256MB
L1-8 1000MS 256MB
L2-1 1000MS 128MB
L2-2 1000MS 128MB
L2-3 1000MS 256MB
L2-4 1000MS 64MB
L3-1 2000MS 64MB

ps:一般來說照弥,64MB內(nèi)存足以。

L1-1 建議改成:空 格 體(5)


Problem Description

LXY 在某大型知名同性交友網(wǎng)站上傳了一個視頻进副,但并沒有想到有意思的標題这揣。作為標題黨的 LXY 想讓博學多識的你給他想一個好標題悔常。

結(jié)合 LXY 的視頻內(nèi)容,你自然想到了一個非常好的標題给赞。為了將自己的標題告訴 LXY机打,你需要在評論區(qū)用建議空格體加入標題競標。

建議空格體示例
Input

輸入共一行片迅,一個由大小寫字母及數(shù)字組成的字符串(不超過 100000 個字符)残邀,表示你想出的標題。

Output

輸出一行柑蛇,開頭是"Proposed change to: "芥挣,后面是標題并將標題內(nèi)的每個字符用空格隔開。

Simple Input

114514

Simple Output

Proposed change to: 1 1 4 5 1 4

Source

CGY

思路

讀取字符串耻台,按要求每一個字符前輸出一個空格即可空免。

這道題部分人用JAVA和C語言多次調(diào)用strlen函數(shù)會導致代碼TLE,因為C語言里strlen函數(shù)的時間復雜度為O(n)盆耽,Java的String類比較慢蹋砚,推薦使用StringBuffer來處理。

代碼
#include <bits/stdc++.h>
using namespace std;
int main(){
    string str;
    cin>>str;
    cout<<"Proposed change to:";
    for(int i = 0;i<str.size();++i) cout<<" "<<str[i];
    return 0;
}

L1-2 多邊形(5)


Problem Description

Veggie最近疲于教小侄子寫紅黑樹摄杂,連多邊形的內(nèi)角和都忘記怎么求了坝咐,想請作為數(shù)學小天才的你幫忙編程解決這個問題。

Input

輸入在一行中給出一個整數(shù)n (3≤n≤10)匙姜,表示多邊形的邊數(shù)畅厢。

Output

在一行中對應輸出n邊形內(nèi)角和的值x冯痢,格式為”Answer: x degree”(不含雙引號)氮昧。

Simple Input

4

Simple Output

Answer: 360 degree

Source

LWH

思路

多邊形內(nèi)角和 = (邊數(shù) - 2) * 180

代碼
#include <stdio.h>
int main()
{
    int n;
    scanf("%d", &n);
    printf("Answer: %d degree", (n - 2) * 180);
    return 0;
}

L1-3 米斯達與數(shù)字4(10)


Problem Description

Guīdo Misuta是《JOJO的奇妙冒險:黃金之風》里面的人物,他對于數(shù)字4很是在意浦楣,他認為4是十分不吉利的數(shù)字⌒浞剩現(xiàn)在有一串數(shù)字,請問這串數(shù)字迫害米斯達的次數(shù)是多少振劳?

迫害次數(shù)=數(shù)字4出現(xiàn)的次數(shù)+數(shù)字長度內(nèi)4出現(xiàn)的次數(shù)椎组。

//性感手槍警告

Input

輸入一串數(shù)字,長度不超過200位

Output

數(shù)字4出現(xiàn)的次數(shù)和數(shù)字長度中4的次數(shù)的總和

Simple Input

1234

Simple Output

2

Hint

數(shù)字中出現(xiàn)4的次數(shù)為1历恐,同時數(shù)字長度為4寸癌,因此總和為1+1=2

Source

LXY

思路

這道題分為兩個部分來求解,一個是求這串數(shù)字中4的個數(shù)弱贼,另一個是這串數(shù)字位數(shù)(長度)中4的個數(shù)蒸苇。
在這里,我們可以采用string字符串來讀入吮旅,借助string.size()函數(shù)來快速得到這串數(shù)字的位數(shù)溪烤,然后將位數(shù)不斷模10整除10來獲得每一位的數(shù)字并統(tǒng)計其中4的個數(shù)。最后遍歷這個字符串,判斷字符為'4'的個數(shù)檬嘀,兩部分累加即為答案槽驶。

代碼
#include <bits/stdc++.h>
using namespace std;
int main(){
    string str;
    cin>>str;
    int n = str.size();
    int cnt = 0;
    while(n){
        if(n%10 == 4) cnt++;
        n/=10;
    }
    for(int i = 0;i<str.size();++i){
        if(str[i]=='4') cnt++;
    }
    cout<<cnt;
    return 0;
}

L1-4 打印(10)


Problem Description

真的是道簡單打印題哈——給定一個整數(shù)數(shù)組nums鸳兽,請打印其中位數(shù)為偶數(shù)且數(shù)值也為偶數(shù)的數(shù)字掂铐。

Input

第一行為一個整數(shù)N(1 \leq N \leq 10),代表數(shù)組nums有N個整數(shù)贸铜。

接下來有N行堡纬,每行有一個整數(shù)A(-2^{30} \leq A \leq 2^{30})

Output

若輸入的A的位數(shù)為偶數(shù)且數(shù)值也為偶數(shù),則打印該行蒿秦。

Simple Input1

3
12
2
13

Simple Output1

12

Simple Input2

2
-1
-12

Simple Output2

-12

Source

SLF

思路

方法一:用字符串處理烤镐,判斷字符串位數(shù)是否為偶數(shù)(負號不算入內(nèi)),再判斷最后一個字符是否為偶數(shù)即可棍鳖。

方法二:直接讀入整數(shù)處理炮叶。

代碼(方法一)
#include <bits/stdc++.h>
using namespace std;
int main(){
    string str;
    int n;
    cin>>n;
    while(n--){
        cin>>str;
        int num_len = str.size();
        if(str[0]=='-'){
            num_len--;
        }
        if(str[str.size()-1]%2==0 && num_len%2==0){
            cout<<str<<endl;
        }
    }
    return 0;
}

L1-5 尋找連座(15)


Problem Description
image.png

軟件學院的LXY和CGY要去一起坐火車外出比賽《纱Γ火車上有許多節(jié)車廂镜悉,每節(jié)車廂的每一排都有4個座位,且這4個座位被過道分成了兩半医瘫。不幸的是侣肄,當LXY和CGY到了車上時,一些位子已經(jīng)有人了醇份。

但LXY和CGY是好基友稼锅,于是他們想要找一對連在一起的座位,以便于更好地打游戲(手動劃掉)學習僚纷。一對連在一起的座位指得是矩距,這兩個座位在同一排且不被過道分割開。已知火車上每節(jié)車廂上的座位情況怖竭,請問能否找得到這樣的一對連座锥债?

Input

第一行為一個整數(shù)N(1≤N≤100),代表火車總長度痊臭。

緊接著輸入N行哮肚,每行由五個字符組成,代表一排座位或者車廂分割線广匙。

若是一排座位允趟,第1、2艇潭、4拼窥、5個字符分別代表一排中的4個座位情況戏蔑,字符'O'表示空座位,字符'X'表示座位上已經(jīng)有人鲁纠,即被占用总棵。第3個字符為'|',代表過道。

若是車廂分割線,則五個字符均為'-'砰苍。

數(shù)據(jù)保證每節(jié)車廂至少有一排座位课竣。

Output

如果能夠找到這樣一組連座室埋,請先輸出一行字符串"Yes"(不輸出引號),接下來一行,輸出一個整數(shù)k,代表這組連座在第k車廂(車廂編號由1開始专酗,從前往后編號遞增)。

接下來輸出火車的座位情況盗扇,將LXY和CGY坐的連座用"+"來表示祷肯。

若不能找到這樣的連座,則輸出一行字符串"No"(不輸出引號)疗隶。

有多組座位符合要求時佑笋,將LXY和CGY安排在靠前的車廂,靠前的排斑鼻,如果同一排還有兩組可行解蒋纬,選擇將LXY和CGY排在左邊。例如:

OO|OO                ++|OO

-----        ->      -----

OO|XX                OO|XX
Simple Input1

6
OO|OX
XO|XX
OX|OO
XX|OX
-----
OO|XX

Simple Output1

Yes
1
++|OX
XO|XX
OX|OO
XX|OX
-----
OO|XX

Simple Input2

6
XO|OX
XO|XX
OX|XO
XX|OX
-----
OX|XX

Simple Output2

No

Source

SLF

思路

字符串處理題坚弱。

遍歷字符串數(shù)組蜀备,判斷出LXY和CGY連座的位置,記錄下來即可史汗。

需要注意得是琼掠,車廂分割線代表著前一節(jié)車廂和后一節(jié)車廂的分割拒垃,可以聯(lián)想火車/高鐵的平面示意圖停撞。有些同學沒有注意到這一點,導致Wrong Answer悼瓮。

代碼
#include <bits/stdc++.h>
using namespace std;

string str[110];

int main(){
    int n;
    cin>>n;
    for(int i = 0;i<n;++i){
        cin>>str[i];
    }
    int cnt = 1;
    int ansi,ansj;
    int flag = false;
    for(int i = 0;i<n;++i){
        for(int j = 0;j<4;++j){
            if(str[i][j]=='-'){
                ++cnt;//統(tǒng)計當前車廂為第幾車廂
                break;
            }
            if(str[i][j]=='O' && str[i][j+1]=='O'){
                flag = true;
                ansi = i,ansj = j;
                break;
            }
        }
        if(flag) break;
    }
    if(flag){
        cout<<"Yes"<<endl;
        cout<<cnt<<endl;
        for(int i = 0;i<n;++i){
            for(int j = 0;j<5;++j){
                if(i==ansi&&j==ansj){
                    cout<<"++";
                    ++j;
                    continue;
                }
                cout<<str[i][j];
            }
            cout<<endl;
        }
    }else{
        cout<<"No"<<endl;
    }
    return 0;
}

L1-6 Heroes never die(15)


Problem Description
image.png

OverWatch里的三個英雄有著上圖的克制關(guān)系戈毒。

現(xiàn)在,我們需要寫一個程序來自動選擇英雄横堡,以對抗對方選擇的英雄埋市。

選擇規(guī)則如下:

1、當回合數(shù)是K的倍數(shù)時命贴,選擇一個相同的英雄道宅。

2食听、當回合數(shù)是N的倍數(shù)時,選擇一個”天使”英雄污茵,并在接下來一行輸出” Heroes never die”樱报。

3、當回合數(shù)是K和N的倍數(shù)時泞当,選擇一個相同的英雄迹蛤。

4、其他回合襟士,選擇一個克制對方英雄的英雄盗飒。

Ps:回合數(shù)從1開始

Input

首先第一行給出兩個整數(shù)K、N(1≤K,N≤10)陋桂,由空格隔開逆趣。隨后每行給出一個對方選擇的英雄:”Mccree”代表”麥克雷”,”Hanzo”代表”半藏”嗜历,”Genji”代表源氏汗贫。End代表輸入結(jié)束,這一行不要做任何處理秸脱。

數(shù)據(jù)保證:回合數(shù)最多不超過2000

Output

參照題意的規(guī)則落包,每次選擇一個英雄,單獨輸出一行摊唇。其中”Mercy”代表”天使”咐蝇,選擇”天使”時,接下來一行要接著輸出”Heroes never die”巷查。(所有輸出均不帶雙引號)

Simple Input1

2 3
Mccree
Hanzo
Genji
Genji
Hanzo
Mccree
End

Simple Output1

Genji
Hanzo
Mercy
Heroes never die
Genji
Mccree
Mccree

Source

SLF

思路

判斷每一回合是否為K或者N的倍數(shù)有序,然后按照題意要求輸出即可。

代碼
#include <bits/stdc++.h>
using namespace std;

int main(){
    string Mccree = "Mccree",Hanzo = "Hanzo",Genji = "Genji";
    int n,k,cnt = 0;
    cin>>k>>n;
    while(true){
        cnt++;
        string str;
        cin>>str;
        if(str == "End") break;
        if(cnt%k==0){
            cout<<str;
        }else if(cnt%n==0){
            cout<<"Mercy"<<endl;
            cout<<"Heroes never die";
        }else{
            if(str == Mccree) cout<<Genji;
            else if(str == Hanzo) cout<<Mccree;
            else              cout<<Hanzo;
        }
        cout<<endl;
    }
    return 0;
}

L1-7 LXY的小機器人(20)


Problem Description

LXY上大三了岛请,他選修了機器人技術(shù)這門課旭寿。期末的大作業(yè)是要寫一段機器人的控制程序,完成某些功能崇败。LXY可以對機器人發(fā)布WSAD四個指令盅称,在二維平面上,指令分別表示:

W:機器人向上走一步(X,Y+1)

S:機器人向下走一步(X,Y-1)

A:機器人向左走一步(X-1,Y)

D:機器人向右走一步(X+1,Y)

LXY的程序會從頭到尾循環(huán)的運行后室,LXY設定的每個指令會在1s內(nèi)完成缩膝,現(xiàn)在LXY想知道經(jīng)過一段時間后,機器人所處在的二維平面上的位置是多少岸霹。(LXY開始時已經(jīng)將機器人放在(0,0)點)

Input

第一行輸入一串由‘W’,‘S’疾层,‘A’,‘D’組成的字符串贡避,表示指令(指令長度不超過2000)
第二行輸入一個數(shù)字N痛黎,表示LXY想知道經(jīng)過N秒后機器人的位置(N<=2000000000)

Output

輸出包括兩個數(shù)字予弧,表示經(jīng)過N秒后機器人的坐標位置,分別為橫坐標和縱坐標

Simple Input1

WSDDWSDAADW
12

Simple Output1

2 2

Source

LXY

思路

模擬題湖饱,但要注意數(shù)據(jù)范圍桌肴,數(shù)據(jù)N <= 2* 10^{9}

所以若直接暴力模擬琉历,時間復雜度為O(N)坠七,在一秒內(nèi)無法完成。這里有許多同學沒有注意到這一點旗笔,導致無法通過最后兩個測試點彪置。

然后我們可以分析可得,完成一次指令周期機器人相對位置變化是固定的蝇恶,而指令周期len最長只有2000拳魁,時間復雜度O(len)是可以接受的。

于是我們可以先算出一個指令周期的相對位置撮弧,然后乘以(N/len)次潘懊,最后我們再模擬一次(N/len)的余數(shù)部分即可。

代碼
#include <bits/stdc++.h>
using namespace std;
int main(){
    string str;
    cin>>str;
    int x = 0,y = 0;
    for(int i = 0;i<str.size();++i){
        if(str[i]=='W') ++y;
        if(str[i]=='S') --y;
        if(str[i]=='A') --x;
        if(str[i]=='D') ++x;
    }
    int len;
    cin>>len;
    x *= (len/str.size());y *= (len/str.size());
    for(int i = 0;i<(len%str.size());++i){
        if(str[i]=='W') ++y;
        if(str[i]=='S') --y;
        if(str[i]=='A') --x;
        if(str[i]=='D') ++x;
    }
    cout<<x<<" "<<y;
    return 0;
}

L1-8 LXY的圓和矩形(20))


Problem Description

LXY上初中了贿衍,數(shù)學老師有一天留下了一個作業(yè)授舟。已知圓上有N個點,給出每個點之間的弧長(為方便)輸入贸辈,給出的弧長已經(jīng)除了π释树,請問這些點一共能構(gòu)成多少個不重復的矩形。

Input

輸入第一行整數(shù)N(N<=100)擎淤,第二行輸入N個整數(shù)奢啥,表示相鄰每兩個點之間的弧長。

Output

輸出N個點所構(gòu)成的不重復的矩形個數(shù)

Simple Input1

8
1 2 2 3 1 1 3 3

Simple Output1

3

Hint
image.png

據(jù)說嘴拢,直徑所對的弦為半圓桩盲;

而且,直徑所對的圓周角為直角席吴;

那么問題來了赌结,矩形有幾個直角呢?

Source

LXY

思路

圓內(nèi)一條直徑對應的兩個圓周角均為直角抢腐,一個矩形有四個直角姑曙,所以兩條直徑確定一個矩形襟交。

我們計算出圓內(nèi)的點能連成多少條直徑迈倍,然后兩兩直徑算一次即可得出矩形數(shù)量。

如果兩個點連接的直線對應的弧長正好為總弧長的一半捣域,則該直線為圓的直徑啼染。

ps:只要兩個矩形四點任意一點不同就視為不同的矩形宴合。這里有一些同學可能考慮復雜了。

代碼
#include <bits/stdc++.h>
using namespace std;
int a[110];
int main(){
    int n,sum = 0,m = 0;
    cin>>n;
    for(int i = 1;i<=n;++i){
        cin>>a[i];
        sum += a[i];
    }
    for(int i = 1;i<=n;++i){
        int t = a[i];
        for(int j = i+1;j<=n-1;++j){
            t += a[j];
            if(t*2 == sum){
                ++m;
                break;
            }
        }
    }
    int res = 0;
    for(int i = 1;i<=m;++i){
        res+=(i-1);
    }
    cout<<res;
    return 0;
}

L2-1 竊取密碼(25)


Problem Description

LWH想要竊取ACM-ICPC系統(tǒng)的管理員密碼迹鹅,以提前查看今年World Final的題目卦洽。為此,他偷偷溜進管理員辦公室斜棚,偷了一張紙阀蒂,上面有一張清單,清單上有著n個密碼弟蚀,密碼均由小寫的英文字母組成蚤霞。管理員密碼就在其中。
LWH回家后义钉,開始準備對系統(tǒng)進行黑客攻擊昧绣。為了破解系統(tǒng),他不得不輸入一個個密碼進行嘗試捶闸。不過幸運得是夜畴,他發(fā)現(xiàn)了這些密碼具有等效性。

  • 如果清單上兩個密碼a和b都包含同一個字母删壮,則密碼a等效于b

  • 如果清單上兩個密碼a和b都等效于c贪绘,則a也等效于b

如果管理員密碼與某個密碼等效,則用戶也可以使用等效的密碼來登錄系統(tǒng)央碟。

例如兔簇,如果清單列表包含密碼”a”, ”b”, ”ab”, ”d”,則”a”, ”b”, ”ab”彼此等效硬耍,但密碼”d”不與清單列表中任何的密碼等效垄琐。所以:

  • 如果管理員的密碼為”b”,那么您可以使用以下任何密碼訪問系統(tǒng):”a”, ”b”, ”ab”经柴。

  • 如果管理員的密碼為”d”,那么您只能使用”d”來訪問系統(tǒng)狸窘。

清單列表中只有一個密碼是測試系統(tǒng)的管理員密碼。請幫助LWH計算能正確進入系統(tǒng)所需的最小密碼數(shù)坯认。請記住翻擒,LWH不知道清單列表中哪個密碼是管理員的密碼。

Input

第一行包含一個整數(shù)n(1≤n≤2*10^5)牛哺,代表列表清單中的密碼數(shù)陋气。

接下來n行,每行一個非空字符串s_i代表密碼引润,s_i長度不超過50個字符巩趁。某些密碼可能一樣。

數(shù)據(jù)保證所有字符串總長度不超過10^6淳附,所有密碼都由小寫英文字母組成议慰。

Output

輸出一個整數(shù)蠢古,代表需要測試密碼的最小數(shù)量,其中這些密碼能夠確保LWH進入系統(tǒng)别凹。

Simple Input1

4
a
b
ab
d

Simple Output1

2

Hint

第一個樣例LWH只需要測試兩個密碼即可草讶,一個密碼為”a”、”b”炉菲、”ab”中的任意一個堕战,因為它們相互具有等效性,另一個密碼為”d”拍霜,所以輸出2践啄。

Source

SLF

思路

題意要求算可以將給出的密碼列表分成多少類,同一類內(nèi)的密碼相互等效沉御。

我們可以用并查集來解決這個問題屿讽。

1、設置一個長度為26的整數(shù)數(shù)組吠裆,分別代表26個英文字母指向哪一個字符串伐谈。

2、遍歷每一個字符串的每一個字符试疙。

3诵棵、若該字符的數(shù)組尚未指向,這將該字符指向這個字符串祝旷。

4履澳、若該字符的數(shù)組已指向,這將該字符串用并查集指向該字符已指向的字符串怀跛。

5距贷、最后統(tǒng)計有多少個字符串指向自己即可。(在并查集中吻谋,每個字符串一開始均指向自己)

ps:如果寫得并查集常數(shù)較大或者沒有進行路徑壓縮忠蝗,只能拿到60%的分數(shù)。暴力查找求解也可以通過部分的測試點漓拾,但是代碼容易寫錯且分數(shù)不高阁最。

代碼
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200010;
int f[MAXN];
int find_father(int x){return f[x]==x?x:f[x]=find_father(f[x]);}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    int flag[110];
    memset(flag,0,sizeof(flag));
    int n;
    cin>>n;
    for(int i = 1;i<=n;++i){
        f[i] = i;
        string str;
        cin>>str;
        for(int j = 0;j<str.size();++j){
            int t = str[j]-'a';
            if(!flag[t]){
                flag[t] = i;
            }
            else{
                int tx = find_father(flag[t]);
                int ty = find_father(i);
                if(tx!=ty){
                    f[tx] = ty;
                }
            }
        }
    }
    int res = 0;
    for(int i = 1;i<=n;++i){
        if(i==find_father(i))
            res++;
    }
    cout<<res;
    return 0;
}

L2-2 愧疚往事(25)


Problem Description

Veggie想起高中注冊時幫了初中語文老師插隊交學費,至今內(nèi)心都因為那次插隊感到無比愧疚骇两。為了能夠讓這件愧疚往事成為教訓速种,Veggie決定通過建立插隊模型來體會那些被插隊者的心情。在模型中低千,每個人都屬于且僅屬于一個朋友圈配阵,圈內(nèi)的人相互之間都是朋友。他們在排隊時,會在隊伍從后往前找熟人闸餐,如果找到了自己的朋友饱亮,就排在朋友后面矾芙,否則才會選擇排到隊伍最后舍沙。Veggie正在為找實習而忙碌,于是請你幫忙編程實現(xiàn)這個模型剔宪。

Input

輸入第一行中給出兩個整數(shù)N拂铡、M,其中N(1 \leq N \leq 100)朋友圈個數(shù)葱绒,M(1 \leq M \leq 10^5)是指令條數(shù)感帅。

隨后N行中,每行給出一個朋友圈的信息地淀。首先是整數(shù)K(1 \leq K \leq 10^3)失球,表示這個朋友圈中的人數(shù),接著是K個人員的編號(00000~99999)帮毁,中間用空格分開实苞。

隨后M行中,每一行給出一條模擬指令烈疚,指令有以下兩種形式:

"IN x": 表示編號為x的人員進入隊伍黔牵。

"OUT": 表示在隊首的人離開隊伍,此時我們需要輸出該人員的編號爷肝。
(注意:指令不含雙引號)

Output

按順序輸出離開隊伍的人員編號猾浦,每個人的編號占一行。如果對空的隊伍使用“OUT”指令灯抛,則輸出”EMPTY”(不含雙引號)金赦。

Simple Input1

3 16
3 00001 00002 00003
3 11111 22222 33333
5 05030 05116 05103 05139 05044
IN 00001
IN 11111
IN 05030
IN 00002
IN 22222
OUT
OUT
OUT
OUT
OUT
IN 00003
IN 05103
IN 05139
IN 00001
OUT
OUT

Simple Output1

00001
00002
11111
22222
05030
00003
00001

Source

LWH

思路

隊列模擬題。

為了處理方便对嚼,我們將每一個朋友圈編號素邪,然后用Map<string,int>來映射每一個人對應的朋友圈編號。(不用Map猪半,也可以用數(shù)組代替相應功能)

然后我們設置一個編號隊列T兔朦,用來存放正在排隊的朋友圈編號。

最后我們給每一個朋友圈都再單獨設置一個隊列Q磨确。

然后開始模擬:

當一個人x想入隊時沽甥,我們先判斷x所在的朋友圈隊列Q是否為空。

  • 若為空證明總隊列中沒有x的朋友乏奥,所以將x入隊到Q中摆舟,同時將x所對應的朋友圈編號i入隊到編號隊列T中。

  • 若不為空證明總隊列中有x的朋友,所以將x入隊到Q中即可恨诱。

當遇到出隊命令時,我們先判斷編號隊列T的隊首元素i,然后將i對應的隊列Q的隊首出隊.然后判斷Q是否為空,是則將隊列T隊首元素i進行出隊處理.

要注意處理遇到出隊命令時媳瞪,需要判斷隊列是否為空,否則會造成Runtime Error照宝。

所有入隊/出隊操作的時間復雜度都是O(lg(K*N))蛇受。

有許多同學直接暴力模擬題意,而沒有考慮到數(shù)據(jù)范圍和算法的時間復雜度厕鹃,造成Time Limit兢仰。

這道題對Java選手不太友好,因為Java讀入和自帶的數(shù)據(jù)結(jié)構(gòu)庫比較慢剂碴,算法正確的前提下可能會導致后面幾個點TLE把将。

代碼
#include <iostream>
#include <cstdio>
#include <string>
#include <queue>
using namespace std;
const int maxn = 1e5+10;
queue<int> q_id;
queue<int> q_member[1005];
int mapping[maxn], isInQueue[1005];
int n, m, k, t;
string str;

int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &k);
        for (int j = 0; j < k; j++) {
            scanf("%d", &t);
            mapping[t] = i;
        }
    }

    while (m--) {
        cin >> str;
        if (str == "IN") {
            scanf("%d", &t);
            if (!isInQueue[mapping[t]]) {
                isInQueue[mapping[t]] = 1;
                q_id.push(mapping[t]);
            }
            q_member[mapping[t]].push(t);
        } else {
            if (q_id.empty()) {
                printf("EMPTY\n");
                continue ;
            }
            int id = q_id.front();
            printf("%05d\n", q_member[id].front());
            q_member[id].pop();
            if (q_member[id].empty()) {
                q_id.pop();
                isInQueue[id] = 0;
            }
        }
    }
    return 0;
}

L2-3 關(guān)心員工(25)


Problem Description

SLF是G市某集團的總裁,他認為能一起打拼的員工都是好兄弟忆矛,因此他十分關(guān)心公司各個層次員工的生活水平察蹲。在公司中,每位員工都有且只有一名直屬上司(SLF除外)催训,而上司有可能有多個下屬員工洽议,于是各級員工之間就有了層次之分。為了更好地給員工補貼瞳腌,SLF會定期統(tǒng)計各層次員工的平均收入绞铃。由于SLF忙于處理集團事務,于是想請你幫忙編程解決這個問題嫂侍。

Input

輸入第一行中給出一個整數(shù)N(1 \leq N \leq 10^5)儿捧,即整個公司的總?cè)藬?shù),每個員工從1到N編號挑宠,總裁SLF的編號為1菲盾。隨后N行,第i行給出編號為i的員工的相關(guān)信息各淀,格式如下:

K \quad N_1 \quad N_2 \quad ... \quad N_K \quad Salary

其中K是一個整數(shù)(0 \leq K \leq20)懒鉴,表示該員工直接下屬員工的個數(shù),N_i是直接下屬員工的編號碎浇,Salary是一個正數(shù)(Salary \leq 2*10^4)临谱,表示該員工的收入。

Output

在一行中對應輸出公司的層次數(shù)m奴璃,隨后m行中輸出各層次員工的平均工資悉默,格式為”Level i: average_i”(不含雙引號),其中average_i表示第i層員工的平均工資,需要保留兩位小數(shù)苟穆。

Simple Input1

7
2 2 3 100
3 4 5 6 2
1 7 3
0 4
0 5
0 6
0 7

Simple Output1

3
Level 1: 100.00
Level 2: 2.50
Level 3: 5.50

Source

LWH

思路

對多叉樹進行層序遍歷抄课,計算每一層員工的平均和有多少層唱星,最后輸出即可。

這里有個注意的點是:題目中的工資Salary是正數(shù)跟磨,而不是整數(shù)间聊,所以輸入的變量要設置為浮點數(shù)。

這個點許多同學沒有注意到從而造成Wrong Answer抵拘,真是令人可惜哎榴。這也表明了同學們讀題能力稍顯薄弱,有待加強啊仑濒。

//你要問題意為什么這么坑叹话?沒辦法偷遗,天梯賽的真題就有這樣坑人的墩瞳。(手動滑稽)

代碼
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>

using namespace std;
const int maxn = 1e5 + 10;
vector<int> tree[maxn];
double num[maxn], salary;
int n, m, root, t;

void bfs(int root) {
    //pre_level表示當前層數(shù),node_num表示本層的節(jié)點數(shù)
    int pre_level = 1, node_num = 0;
    //本層的平均值
    double avg = 0;
    vector<double> ans;
    queue<pair<int, int> > q;
    q.push(make_pair(root, 1));
    while (!q.empty()) {
        int node = q.front().first;
        int level = q.front().second;
        q.pop();
        //當去到新的一層就統(tǒng)計上一層的數(shù)據(jù)
        if (level != pre_level) {
            ans.push_back(avg / node_num);
            node_num = 0;
            avg = 0;
            pre_level = level;
        }
        //數(shù)量和工資的累計
        node_num++;
        avg += num[node];
        //將所有的子節(jié)點放入隊列中
        for (int i = 0; i < tree[node].size(); i++) {
            q.push(make_pair(tree[node][i], level + 1));

        }
    }
    //由于最后一層無法再到達新的一層氏豌,所以要單獨計算
    ans.push_back(avg / node_num);

    //輸出結(jié)果
    printf("%d\n", pre_level);
    for (int i = 0; i < ans.size(); i++) {
        printf("Level %d: %.2f\n", i + 1, ans[i]);
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> m;
        for (int j = 0; j < m; j++) {
            cin >> t;
            tree[i].push_back(t);
        }
        cin >> salary;
        num[i] = salary;
    }
    bfs(1);
    return 0;
}

L2-4 奇怪的需求增加了.jpg(25)


Problem Description

自從復工以來喉酌,CGY 一直在接一些奇怪的需求,需求多到做都做不完(他急了泵喘,他急了)泪电。由于 CGY 是單核單線程處理器(Intel 賽揚 B720),所以他每次只能同時做一個需求〖推蹋現(xiàn)在 CGY 手上堆了 N 個需求相速,每個需求都需要一段時間完成,如果他在一定時間內(nèi)沒有完成某個需求鲜锚,那么這個需求就會被他的師兄憶兔之心拿過去做突诬,這樣憶兔之心就有可能抓到 CGY 把之前趕需求的時間都用來打雀魂(而且還上不了雀圣)的把柄。為了防止被發(fā)現(xiàn)芜繁,CGY 需要完成盡可能多的需求旺隙,那你能幫幫他嗎?

9c551c53ca.png
Input

第一行是一個整數(shù) N(N <= 150000)骏令。

接下來 N 行每行兩個整數(shù) T_1T_2蔬捷,描述了一個需求:完成這個需求需要 T_1 小時,如果在 T_2 小時之內(nèi)還沒有完成(如果剛好在 T_2 時刻完成也算完成榔袋,踩點不算遲到嘛)周拐,這個需求就被撈走了。(數(shù)據(jù)保證 T_1 <= T_2 <= 1e15

Output

輸出一個整數(shù) S凰兑,表示最多可以完成 S 個需求妥粟。

Simple Input1

4
100 200
200 1300
1000 1250
2000 3200

Simple Output1

3

Source

CGY

思路

堆+貪心。

我們可以先按照T_{2}進行升序排序聪黎,然后遍歷這些需求罕容。遍歷的同時維護一個nowtime(代表現(xiàn)在的時刻)备恤,如果當前需求能夠被滿足,就將這個需求加入到優(yōu)先隊列PQ(其中PQ是T_{1}的大根堆)锦秒。如果當前需求不能被滿足露泊,則判斷當前需求能否替換掉PQ頂端的需求,可以的話就替換旅择,另外需要注意替換后nowtime可能會發(fā)生變化惭笑。這樣替換并不會造成錯誤,因為我們已經(jīng)對需求進行排序生真,所以替換對PQ中的其他需求不會產(chǎn)生沖突沉噩。

代碼
#include <bits/stdc++.h>

using namespace std;

int n;
pair<long long, long long> needs[150010];
priority_queue<long long> pq;
int ans;
long long last;

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> needs[i].second >> needs[i].first;
    }
    sort(needs, needs + n);
    for (int i = 0; i < n; ++i) {
        if (last + needs[i].second <= needs[i].first) {
            ++ans;
            last += needs[i].second;
            pq.push(needs[i].second);
        } else if (!pq.empty() && needs[i].second < pq.top()) {
            last += needs[i].second - pq.top();
            pq.pop();
            pq.push(needs[i].second);
        }
    }
    cout << ans << endl;

    return 0;
}

L3-1 《還債啦!動物森友會》(30)


Problem Description

Dr.Su 每天辛苦工作柱蟀,缺乏休息時間川蒙,只能深夜在夢里玩動物之森聊以慰藉。在夢里长已,帶資本家貍吉還是那個貍吉畜眨,西施惠還是那個西施惠,該還的貸款還是要還术瓮。于是康聂,Dr.Su 給夢里的這個版本起名叫《還債啦!動物森友會》胞四。

在《還債啦恬汁!動物森友會》里,賺錢的唯一方法是——從地上收集樹枝賣錢(這才是真正的里數(shù)挑戰(zhàn))辜伟。這次的無人島是一個 N × M 的長方形島嶼(難道哪一次不是嗎氓侧?),第 ij 列的格子內(nèi)可以收集到 C_{ij} 個樹枝游昼。Dr.Su 只會向上下左右四個方向走甘苍,并且不能離開這座無人島(離開了貍吉會把你綁回來繼續(xù)打工的),每當他走到一個格子烘豌,就會花費一個單位的時間將格子內(nèi)的樹枝全部收集完载庭。眾所周知,這是一個神(keng)奇(die)的島嶼廊佩,所以當 Dr.Su 收集完并離開某一格子后囚聚,該格子會重新刷新出原來所有的樹枝。

Dr.Su 建的房子(房子所在的格子沒有樹枝)在第 AB 列标锄,他從這里出發(fā)顽铸,花費 K 單位的時間收集樹枝,且 K 單位時間過后他恰好回到自己的房子料皇,請問他最多能采集多少樹枝谓松?

(什么星压?你問 Dr.Su 這么聰明為什么不自己算?有動森玩誰還做題肮砥D缺臁)

微信圖片_20200328141305.jpg
Input

第一行共五個正整數(shù),分別是行數(shù) N(1 <= N <= 100)优质、列數(shù) M(1 <= M <= 100)竣贪、房子位置 A(1 <= A <= N)B(1 <= B <= M) 和時間 K(K <= 1e9)巩螃,保證 K 是偶數(shù)演怎。

接下來 N 行每行 M 個非負整數(shù) C_{ij}(0 <= C_{ij} <= 1e9),表示對應位置樹枝的數(shù)量避乏。且保證 C_{AB} = 0爷耀。

Output

一個整數(shù),表示 Dr.Su 能采集到的最多的樹枝數(shù)淑际。

Simple Input1

2 2 1 1 2
0 1
2 1

Simple Output1

2

Simple Input2

2 2 1 1 4
0 5
5 10

Simple Output2

20

Simple Input3

3 3 2 2 6
5 1 0
1 0 3
1 3 3

Simple Output3

15

Source

CGY

思路

登頂題畏纲。

首先扇住,Dr.Su的路徑可以視作原路返回春缕。因為路徑采摘樹枝數(shù)sum = 去時采摘的樹枝數(shù)x + 回時采摘的樹枝數(shù)y,如果x是最優(yōu)的x艘蹋,那么想要sum最大锄贼,那么y必定 = x。所以我們可以將時間K/2女阀,只需要算x宅荤,最后答案 = x*2。

所以我們可以進行搜索處理浸策,但由于時間K最大有1e9,所以會超時。

其次春瞬,我們分析可得山上,如果K/2 > n*m,那么Dr.Su會在最后一定會轉(zhuǎn)圈圈蚯舱,而且圈的周長等于2改化,也就說Dr

.Su會在兩個格子之間反復橫跳。因為我們可以假設如果圈的周長 = n枉昏,那么這n個格子里面一定可以選出兩個格子使得這兩個格子的樹枝數(shù)/2 >= n個格子的樹枝數(shù)/n陈肛。

所以如果K/2 > n*m,那么我們只用對全部格子記憶化搜索n*m次即可兄裂。

代碼一
#include <bits/stdc++.h>

using namespace std;

#define INF 0x7f7f7f7f

long long n;
long long m;
long long a;
long long b;
long long k;
long long c[110][110];
long long dp[110][110][2];
long long ans;
long long dx[4] = {-1, 0, 1, 0};
long long dy[4] = {0, 1, 0, -1};
long long step;
int tag = 0;

bool check(int x, int y) {
    return !(x < 1 || y < 1 || x > n || y > m);
}

int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m >> a >> b >> k;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            cin >> c[i][j];
            dp[i][j][0] = dp[i][j][1] = -INF;
        }
    }
    k /= 2;
    step = min(k, n * m);
    dp[a][b][0] = 0;
    for (int i = 1; i <= step; ++i) {
        tag ^= 1;
        for (int row = 1; row <= n; ++row) {
            for (int col = 1; col <= m; ++col) {
                long long maxp = -INF;
                long long maxc = -INF;
                for (int dir = 0; dir < 4; ++dir) {
                    int newx = row + dx[dir];
                    int newy = col + dy[dir];
                    if (check(newx, newy)) {
                        maxp = max(maxp, dp[newx][newy][1 ^ tag]);
                        maxc = max(maxc, c[newx][newy]);
                    }
                }
                if (maxp != -INF) {
                    dp[row][col][tag] = maxp + c[row][col];
                    ans = max(ans, dp[row][col][tag] * 2 - c[row][col] + (maxc + c[row][col]) * (k - i));
                }
            }
        }
    }
    cout << ans << endl;

    return 0;
}
代碼二(ZLM大師37ms的代碼orz)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

const int dir_x[] = {0, 0, -1, 1};
const int dir_y[] = {-1, 1, 0, 0};
const int MAXN = 101;

long long dp[MAXN][MAXN], ss[MAXN][MAXN];
int s[MAXN][MAXN], step[MAXN][MAXN];

int main() {
    int n, m, a, b, k;
    memset(dp, 0xFF, sizeof(dp));
    scanf("%d%d%d%d%d", &n, &m, &a, &b, &k);
    k >>= 1;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", s[i] + j);
    memset(ss, 0, sizeof(ss));
    for (int x = 1; x <= n; ++x)
        for (int y = 1; y <= m; ++y) {
            for (int i = 0; i < 4; ++i) {
                int xx = x + dir_x[i];
                int yy = y + dir_y[i];
                if (!xx || xx > n || !yy || yy > m) continue;
                ss[x][y] = std::max(ss[x][y], (long long)s[x][y] + s[xx][yy]);
            }
        }
    long long ans = 0;
    std::queue< std::pair< int, int > > q;
    q.push(std::make_pair(a, b));
    dp[a][b] = 0;
    step[a][b] = 0;
    while (!q.empty()) {
        int x = q.front().first, y = q.front().second;
        q.pop();
        if (step[x][y] > k) break;
        long long left = k - step[x][y];
        left *= ss[x][y];
        ans = std::max(ans, (dp[x][y] << 1) + left - s[x][y]);
        for (int i = 0; i < 4; ++i) {
            int xx = x + dir_x[i];
            int yy = y + dir_y[i];
            if (!xx || xx > n || !yy || yy > m) continue;
            long long tmp = dp[x][y] + s[xx][yy];
            if (dp[xx][yy] == -1 || dp[xx][yy] + ((step[x][y] + 1 - step[xx][yy]) >> 1) * ss[xx][yy] < tmp) {
                dp[xx][yy] = tmp;
                step[xx][yy] = step[x][y] + 1;
                q.push(std::make_pair(xx, yy));
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}

總結(jié)

這次比賽的前10名榜單每隔幾分鐘就會發(fā)生變化句旱,競爭非常激烈阳藻。

這套題目的Lv1難度相對較低,所以主要拉開差距的題目在于Lv2數(shù)據(jù)結(jié)構(gòu)方面的題目谈撒,這也和天梯賽現(xiàn)場賽題目的難度分布相同稚配。如果同學們感覺做Lv2數(shù)據(jù)結(jié)構(gòu)的題目稍顯吃力,表明數(shù)據(jù)結(jié)構(gòu)這方面有待加強港华。

無論結(jié)果如何道川,盡了自己最大的努力便是成功。沒有入圍隊伍名單的同學不用氣餒立宜,好好準備接下來的藍橋杯等賽事吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冒萄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子橙数,更是在濱河造成了極大的恐慌尊流,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灯帮,死亡現(xiàn)場離奇詭異崖技,居然都是意外死亡,警方通過查閱死者的電腦和手機钟哥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門迎献,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腻贰,你說我怎么就攤上這事吁恍。” “怎么了播演?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵冀瓦,是天一觀的道長。 經(jīng)常有香客問我写烤,道長翼闽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任洲炊,我火速辦了婚禮感局,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘选浑。我一直安慰自己蓝厌,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布古徒。 她就那樣靜靜地躺著拓提,像睡著了一般。 火紅的嫁衣襯著肌膚如雪隧膘。 梳的紋絲不亂的頭發(fā)上代态,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天寺惫,我揣著相機與錄音,去河邊找鬼蹦疑。 笑死西雀,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的歉摧。 我是一名探鬼主播艇肴,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼叁温!你這毒婦竟也來了再悼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤膝但,失蹤者是張志新(化名)和其女友劉穎冲九,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體跟束,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡莺奸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冀宴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灭贷。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖花鹅,靈堂內(nèi)的尸體忽然破棺而出氧腰,到底是詐尸還是另有隱情,我是刑警寧澤刨肃,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站箩帚,受9級特大地震影響真友,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜紧帕,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一盔然、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧是嗜,春花似錦愈案、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丽柿,卻和暖如春恢准,著一層夾襖步出監(jiān)牢的瞬間魂挂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工馁筐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涂召,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓敏沉,卻偏偏與公主長得像果正,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子盟迟,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容