2021年 B站1024程序節技術對抗賽

Bilibili 1024: https://b23.tv/PjP70N

 

技術對抗賽


 

算法與安全答題


 

1. 給定有 n 瓶水和4只老鼠,n 瓶水中 最多有1瓶有毒,老鼠喝了有毒的水之後(無論劑量)1天后就會死亡,問如果只給定一天的時間來測試哪一瓶水有毒,n 最大值爲多少?

A. 9      B.12   C. 15   D.16

解題思路

直覺來想這個問題,如果不限制一天時間,一個確定多瓶水中哪一瓶有毒的思路是通過2分法,每一次1只老鼠喝一半數量瓶數的水的混合成品後,即可定位一半瓶數的水是否有毒。這樣,對於16瓶水來說,第一天定位到8瓶內,第二天定位到4瓶內,第三天定位到2瓶內,第四天過完後,定位到最終是哪一瓶有毒。這種方法,需要4天確定16瓶子水中哪一瓶有毒,最多需要4死只老鼠,最好的情況1只老鼠都不用死。

很明顯,這種思路不符合題目只給一天的時間的要求。仔細審題,重點:“只給一天時間”,“老鼠喝到毒需要一天時間才能知道是否有毒”

老鼠喝水,要麼死(1),要麼活(0),也就是單獨一隻老鼠能提供的信息狀態有 1或0 兩個狀態。此時最多隻能用來檢測1瓶水是否有毒。

兩隻老鼠,各自喝水,也是要麼死要麼活,此時兩隻老鼠能提供的信息狀態爲 4 個,因爲此時要麼都沒死(11),  要麼都沒死(00), 要麼一死一活(10 或 01),這是兩隻老鼠喝水能夠提供的最大信息狀態數。如何設計實驗,讓老鼠喝水能在一天時間得到這些信息狀態的可能呢?

嘗試一

我們給3瓶水編號 1,2,3. 第一隻(A)喝1號,第二隻老鼠(B)喝2號,然後等一天,兩隻都死(11)的情況是不可能的,因爲這裏最多有1瓶有毒;如果一死一活(10 或 01),可以分別確定1號或2號有毒;如果兩隻都沒死(00),那隻能確定1和2沒毒,但是3有沒有毒由於沒有老鼠去喝,所以不能確定3號有沒有毒。換句話說,這個嘗試的方案無法百分百確定3瓶水中,沒被喝的那瓶水的情況。我們發現,這裏(10)(01)(00) 三種信息狀態被用於推理,而(11)這種信息狀態被浪費了,2只老鼠是否死亡的情況能提供的4個信息狀態,只用了3個。

嘗試二

我們可以給3瓶水編號 1,2,3. 從二進制看這個編號分別爲 01,10,11.  如果我們把1號給第二隻老鼠(B)喝,2號給第一隻(A),3號水同時給兩隻老鼠(AB)喝,

老鼠代號   A    B

編號(  1)    0    1     給 B

編號(  2)    1    0     給 A

編號(  3)    1    1     給 AB

這樣,如果 AB 都死了(11),說明 3 號有毒,因爲 3號都給了 AB;如果A死B沒死(10),說明 2 號有毒,因爲 B 喝了1和3號,只有2號沒喝;如果A沒死B死(01),說明 1號有毒,因爲 A喝了2和3,只有 1 沒喝;如果AB都沒死(00),則說明3瓶水都沒毒,因爲A喝了2和3,B喝了1和3,如果有其中任意一瓶有毒,AB一定有死的,所以只能說明每一瓶都沒毒。

總結:

通過上面的設計,我們得到了這樣一個方案,能夠用上2只老鼠是否死亡的情況能提供的所有 4 個信息狀態,1天之內,通過以恰當的方式給老鼠喝不同的水,通過每隻老鼠是否死亡,可以明確確定 3 瓶水中是否全沒毒,或哪一瓶水有毒。

可以看到,上面使用的這種 “恰當的方式” 爲:將瓶子從1開始編號,從二進制的角度來看編號,每個二進制位對應一隻老鼠(3個位數對應3只,4個位數對應4只),每瓶水給其編號中二進制數爲 1的那一位老鼠喝,這樣一天後,每一位老鼠的死和活對應於1和0,連起來構成的老鼠個數的位置的二進制數,即定位了唯一的那一瓶水。

不難發現,1只老鼠最多用來定位1瓶水的情況,2只老鼠最多定位 2^2-1=3瓶水的情況,3只老鼠最多定位2^3-1=7瓶水,4只老鼠最多定位 2^4-1=15瓶水的情況,n只老鼠最多定位 2^n-1瓶水的情況

網友評論

網友說爲什麼不可以是 16 瓶

這裏比需要搞清楚這個解決方案的本質,4只老鼠的生死(01)最多在1天時間內最多隻能給出 2^4 = 16 種狀態,其中 0000 表示的是每隻老鼠都喝了,但是每一瓶都沒有毒,所以沒有老鼠死去。

注意這種情況並不多餘,因爲題目中說:最多有1瓶有毒 (不是必有一瓶毒藥,而是可以都沒毒,有毒的話也最多1瓶).

如果給定 16 瓶水和4只老鼠的話,按照這個實驗思路,4 個二進制位(4只老鼠), 0000~1111 這16個狀態(對應 "沒有1瓶有毒" 1種狀態 或 "瓶子編號1~15某一瓶有毒" 15種狀態)位已經不足以承載 17 個信息量("沒有1瓶有毒" 1種狀態 或 "瓶子編號1~16某一瓶有毒" 16種狀態),這時必然需要多 1 只老鼠這個解答思路纔有可能。


 

2. 計算100到10000(包含10000)所有偶數相加結果。(本題由UP主@python學習者提供)
A:  20002550
B:  25002550
C:  20502550
D:  25002050

解題思路:100 + (10000+102)x(10000-100)/2/2


 

3.期末考試結束了,老師決定帶學生們去捲餅店喫烤鴨餅。老師看到大餅和鴨子,搞了一個活動:每人可以拿走一張餅,誰捲到的食物美味程度總和最高,誰就能獲得稱號:卷王之王!Vita很想得到“卷王之王”稱號,他的大餅可以裝下大小總和不超過500的食物,現在有7塊鴨肉和6根黃瓜,每份食物都有它的大小和美味程度。 每塊鴨肉的大小:85、86、73、66、114、51、99 每塊鴨肉的美味程度:71、103、44、87、112、78、36 每根黃瓜的大小:35、44、27、41、65、38 每塊黃瓜的美味程度:41、46、13、74、71、27 老師要求大餅裏至少有一塊鴨肉和一根黃瓜。請問,Vita捲到的食物美味程度總和最大是多少?(本題由UP主@小學生Vita君提供)

A. 593   B.612    C.496   D. 584

解題思路:01 揹包算法(01揹包問題 之 動態規劃(通俗解釋)

容器 500

鴨肉 :85、  86、 73、66、114、51、99

美味: 71、103、44、87、112、78、36

黃瓜: 35、 44、  27、  41、 65、 38

美味: 41、 46、  13、  74、  71、 27

#include <vector>
#include <iostream>

//解決方案
class solution
{
public:
    solution(int value):totalValue(value) {}
    int totalValue;             //選擇的物品的總價值
    std::vector<size_t> items;  //選擇的物品的項
    int containerValue;         //容器容量
};

//構建網格
solution buildNet(const std::vector<size_t>& w, const std::vector<int>& v, size_t total)
{
    size_t row = w.size();      //可選擇的物體數量
    size_t column = total;      //總容量

    std::vector<std::vector<solution>> net;
    net = std::vector<std::vector<solution>>(row+1, std::vector<solution>(column+1, 0));  //初始化多第一行和第一列,便於通用公式

    for (size_t r = 1; r <= row; ++r)
    {
        for (size_t c = 1; c <= column; ++c)
        {
            size_t weightCurrent = w[r - 1]; //當前物品重
            int valueCurrent = v[r - 1];  //當前物品價值
            if (weightCurrent <= c)       //如果單獨放得下
            {
                int valueIncludeCurrent = valueCurrent + net[r - 1][c - weightCurrent].totalValue;
                if (valueIncludeCurrent > net[r - 1][c].totalValue) //加入當前物品價值更高,則更新方案
                {
                    net[r][c] = valueIncludeCurrent;

                    net[r][c].items = net[r - 1][c - weightCurrent].items; //得到之前的序列
                    net[r][c].items.push_back(r);                          //添加自己到序列後
                }
                else
                    net[r][c] = net[r - 1][c];
            }
            else
                net[r][c] = net[r - 1][c];
        }
    }

    net[row][column].containerValue = total;
    return net[row][column];
}

//打印選擇的最佳方案
void printVector(const std::vector<size_t>& w, const std::vector<int>& v,const solution & s)
{
    std::cout << "Input: ";
    for (size_t i = 0; i < w.size(); ++i)
    {
        std::cout << w[i] << " (" << v[i] << ");" ;
    }
    std::cout << "Container: " << s.containerValue << std::endl;

    const std::vector<size_t>& items = s.items;
    int totalV = s.totalValue;

    size_t totalW = 0;
    size_t totalV2 = 0;
    for (auto r : items)
    {
        size_t w0 = w[r-1];
        int v0 = v[r-1];
        std::cout << w0 << " (" << v0 << ");" << std::endl;

        totalW += w0;
        totalV2 += v0;
    }
    std::cout << "Total: " << totalW << " (" << totalV << " -> check:" << totalV2 << ")";
    std::cout << std::endl << std::endl;
}

int main()
{
     std::vector<size_t> w2 = { 85, 86, 73, 66, 114, 51, 99 };
     std::vector<int> v2 = { 71,103,44, 87, 112, 78, 36 };
     solution duck = buildNet(w2, v2, 500);
     printVector(w2, v2, duck);

     std::vector<size_t> w3 = { 35, 44,  27,  41, 65, 38 };
     std::vector<int> v3 = { 41, 46, 13, 74, 71, 27 };
     solution cucumber = buildNet(w3, v3, 500);
     printVector(w3, v3, cucumber);

     std::vector<size_t> w4 = w2;  w4.insert(w4.end(), w3.begin(), w3.end());
     std::vector<int> v4 = v2; v4.insert(v4.end(), v3.begin(), v3.end());
     solution duckCucumber = buildNet(w4, v4, 500);
     printVector(w4, v4, duckCucumber);

    return 0;
}
算法實現參考

運行結果:

 


 

4. 一個小孩練習爬臺階,一共10級臺階,小孩可以一次向上選擇爬1-3級。但是第3級和第6級臺階被施加了魔法,小孩一旦踏上就會停下來就開始跳《新寶島》。那麼,不讓小孩跳《新寶島》的爬法一共有多少種?(本題由UP主@魔法小分隊隊長提供)
A. 46   B. 40  C. 42   D.44

 解題思路:組合不多,使用暴力法

#include <vector>
#include <iostream>

int newCount = 0;
int deleteCount = 0;

class node
{
public:
    node() { ++newCount; }
    ~node() { ++deleteCount; }

    int total = 0;
    int left = 0;
    int currentStep = 0;
    int currentPosition = 0;

    std::vector<node*> nextList;
};

class StairStepCombination {

    std::vector<node*>buildTree(int total, int left, int maxStep)
    {
        std::vector<node*> nextList;
        for (int i = 1; i <= maxStep && i <= left; ++i)
        {
            node* n = new node;
            n->currentStep = i;
            n->left = left - n->currentStep;
            n->currentPosition = total - n->left;
            n->total = total;
            n->nextList = buildTree(total, n->left, maxStep);
            nextList.push_back(n);
        }
        return nextList;
    }

    std::vector<std::vector<node*>> stepList;

    void travelSteps(node* n, std::vector<node*> stepCurrent)
    {
        stepCurrent.push_back(n);
        if (n->nextList.empty())
            stepList.push_back(stepCurrent);
        else
        {
            for (auto next : n->nextList)
                travelSteps(next, stepCurrent);
        }
    }

    void freeTree(node* n)
    {
        for (auto& next : n->nextList)
            freeTree(next);
        delete n;
    }

public:
    int main()
    {
        std::cout << "newCount:" << newCount <<  "  deleteCount:" << deleteCount << std::endl;

        std::vector<node*> nextList = buildTree(10, 10, 3);

        std::cout << "newCount:" << newCount << "  deleteCount:" << deleteCount << std::endl;

        for (auto next : nextList)
            travelSteps(next, {});

        int countTotal = stepList.size();
        int count3And6 = 0;
        for (size_t i = 0; i < stepList.size(); ++i)
        {
            auto& list = stepList[i];
            std::cout << "List[\t" << i + 1 << "]:";
            bool contains3Or6 = false;
            for (auto n : list)
            {
                std::cout << "\t" << n->currentStep << "(" << n->currentPosition << ")";
                if (n->currentPosition == 3 || n->currentPosition == 6)
                    contains3Or6 = true;
            }
            if (contains3Or6)
                ++count3And6;

            std::cout << "\n";
        }

        std::cout << "countTotal:" << countTotal << "  count3And6:" << count3And6 << "  countOK:" << countTotal - count3And6 << std::endl;

        for (auto next : nextList)
            freeTree(next);

        std::cout << "newCount:" << newCount << "  deleteCount:" << deleteCount << std::endl;
        return 0;
    }
};
遍歷所有組合

 


5. 狸子找了一名粉絲做遊戲,初始每人財富相等,每輪遊戲中每個人都要付1元隨機(等概率)給兩人中的一人,記每輪遊戲後最富和最窮玩家的差距爲x(每個人的財富不設上下限),則在足夠多的n輪遊戲後,以下描述正確的是?(本題由UP主@狸子LePtC提供)

A:  x正比於根號n增加

B:  x正比於n的2次方增加

C:  x在0附近波動

D:  x正比於n增加

答案:B, 還不理解,找了一名粉絲也就是總共兩人?沒人每次拿錢給自己和對方還是等概率,也就是給你的機會是 1/2, 給自己的機會也是 1/2,輪流給,也就是:

自己1元有兩種結果,得到自己的1元,失去自己的1元;對方的1元有兩種結果,得到對方的1元,失去對方的1元;

那麼每輪有4種情況,得到自己的1元和對方的1元 1/2x1/2=1/4;   得到自己的1元失去對方的1元 1/4, 失去自己的1元得到對方的1元 1/4;失去自己的1元和對方的1元,1/4

每輪多1元的概率爲 1/4 ,少1元的概率爲 1/4,  不賺不少的概率爲 1/2.  多1和少1的概率都是 1/4, 那麼當次數越來越多,每輪概率概率不變,那麼應該是差距在 0 附近波動纔對呀!


6.   現有5個元素,它們各不相同,且兩兩之間可比較。我們可以通過反覆比較兩個元素的大小,來找出5個元素中的中位數。請問最少用多少次比較,可以確保總能找到 5個元素的中位數?(本題由UP主@算法主義提供)
A:  8次           B:  6次           C:  7次               D:  9次

分析過程:B ?

BCDE  都和 A 比較,確定比 A 大的和比 A 小的,4 次
假設最壞情況,都比 A 大
CDE 和 B比較,確定比 B 大還是比 B 小,3 次
假設最壞情況,都比 B 大
DE 和 C 比較,確定比 C 大還是比 C 小,2 次
假設最壞情況,都比 C 小  (AB x x C)
比較 DE,這是最後的比較, 1 次


 7. 電視劇《征服》於 2003-03-18 上映,在第九集中,劉華強將賣瓜商販捅傷,假設捅人劇情發生在 2003-03-26 日,問賣瓜商販距今 2021-10-24 ,已經被捅了多少天?(本題由UP主@Jack-Cui提供)
A:  6769天
B:  6789天
C:  6777天
D:  6787天
答案: https://riqicha.bmcx.com/?kaishi=2003-03-26-00-00-00&jieshu=2021-10-24-00-00-00


8.  香鍾(又名火繩鍾)是一種使用燃燒香計時的方法,採用榆樹皮粉加入少量秸稈和自然元素,配合一定比例的水攪拌均勻後倒模製成香,根據倒模出不同長度、粗細的香,經過燃燒測量可以生產出各種單位時間的計時香,例如辰香(2小時),刻香(15分鐘)等。 土堡會戰中,上將軍安排左右前衛營於醜時出發,約定出發後5刻(1小時15分)分別從敵人大本營西側與北側奇襲敵營。營中刻香由於保管不當盡毀,目前營中只有辰香,且辰香不能折斷也無法均勻分割,作爲左前衛營行軍參謀的你要拿出具體的計時方案。請問要想確定出5刻的時長,至少需要多少根辰香?(本題由UP主@黑馬程序員提供)
A: 6根
B: 4根
C: 3根
D: 5根

思路分析:可以兩端同時點,並且可以且只能通過另1根的燃燒爲自己記時。這裏 1 小時好解決,同時點1根辰香的2端,燒完既是1小時;只要解決 15分鐘 (1/8個時辰)即可。同時燒1次,可以得到 1/2 個計量單位,那麼通過類似的方法同時燒3次,則可以得到1/8個時辰。

具體操作:提前! 提前! 提前!拿三根abc,a 兩端都點,b只點1端,c 也只點1端。當a燒時,b和c都燒了1半(各可計1個時辰),此時再點b的另1端,當b燒完,又過了0.5小時,此時 c 還剩下 0.5 小時(1/4個時辰),將 c 掐滅備用。

在丑時,繼續將 c 兩端都點,可以知道,c 燒完就是 15 分鐘;然後再拿出1根 d,也是兩端都點上。

這樣,通過 abcd 可計時 1小時15分


9. 有一根長27釐米的細木杆,在第3釐米、7釐米、11釐米、17釐米、23釐米這五個位置上各有一隻螞蟻。木杆很細,不能同時通過兩隻螞蟻。開始時,螞蟻的頭朝左還是朝右是任意的,它們只會朝前走或調頭,但不會後退。當任意兩隻螞蟻碰頭時,兩隻螞蟻會同時調頭朝反方向走。假設螞蟻們每秒鐘可以走一釐米的距離,求所有螞蟻都離開木杆的最短時間和最長時間。(本題由UP主@IT私塾提供)
A: 13;25
B: 11;24
C: 12;23
D: 10;26

解題思路:最快當然是各自完最近的走,3,7,11 往 0 的位置走,17,23 往28 位置走;11-0=11;28-17=11;最快 11 ,答案已出


 10. 半仙君和粉絲兩人打賭,每人喊1-3中的一個數,誰先喊到30誰贏,請問先喊幾有穩贏的可能性?(本題由UP主@半仙君_提供)
A:  1      B:2     C:根本贏不了   D: 3

提供的答案: 2

??????

這問題描述讓人很困惑,難道是說喊完1個數 n 後另一個人就只能每次加1,喊出 n+1,所以先喊的那個需要先喊出個 偶數 ?搞不懂這題,似乎都沒表達清楚


 

安全攻防挑戰賽   https://security.bilibili.com/sec1024/


 

 

安全攻防--1:題目ID:1題目地址https://security.bilibili.com/sec1024/q/r1.html

1024程序員節,大家一起和2233參與解密遊戲吧~
happy_1024_2233:
e9ca6f21583a1533d3ff4fd47ddc463c6a1c7d2cf084d3640408abca7deabb96a58f50471171b60e02b1a8dbd32db156

提示:https://baike.baidu.com/item/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86/468774

分析過程:https://blog.csdn.net/weixin_59725175/article/details/120952089

 

安全攻防--2:題目ID:2題目地址https://security.bilibili.com/sec1024/q/r2.html
 
某高級前端開發攻城獅更改了一個前端配置項
https://security.bilibili.com/sec1024/q/
提示: https://cli.vuejs.org/zh/config/#productionsourcemap
 
 
 
安全攻防--3:題目ID:3題目地址https://security.bilibili.com/sec1024/q/r3.html
PHP is the best language for web programming, but what about other languages?
https://security.bilibili.com/sec1024/q/eval.zip
提示:https://www.php.net/manual/zh/function.preg-match.php
 
 
 
安全攻防--4:題目ID:4題目地址https://security.bilibili.com/sec1024/q/r4.html
 懂的都懂
https://security.bilibili.com/sec1024/q/
 
提示: https://baike.baidu.com/item/sql%E6%B3%A8%E5%85%A5/150289
 
 
破解逆向--5:題目ID:5題目地址https://security.bilibili.com/sec1024/q/r5.html
 
破解逆向--6:題目ID:6題目地址https://security.bilibili.com/sec1024/q/r5.html
 安卓程序員小明學習了新的開發語言,興奮地寫了一個demo app


提示: https://developer.android.com/training/articles/perf-jni?hl=zh-cn
  

風控--7:題目ID:7        題目地址:https://security.bilibili.com/sec1024/q/r7.html

 

 

 

歡迎來到嗶哩嗶哩星球!

 

這裏記錄了前往二次元世界的祕密

安全研究員小孫在早上的時候發現了一波異常流量在訪問網站,他初步篩選了這些可疑的請求,請幫他找到所有的惡意 IP 。
flag 生成方式:找到所有的惡意 IP 後,通過通過英文逗號分隔成一個字符串後提交,系統會根據提交的 IP 正確數計算分數。
PS: 解題過程可發送至 [email protected], 標題: 1024-sec-r7-[你的 mid] 。我們會挑選3位,給予額外驚喜
日誌下載

 

 


安全攻防挑戰賽參考答案: https://www.bilibili.com/read/cv13705903

分析過程參考: https://blog.csdn.net/Arnold_lee_yc/article/details/120973610


感覺這個活動挺有趣的,想着重在參與答一答題,1024那天才看到這個活動,前幾天上班沒時間,算法與安全答題中一些題都是熬夜去嘗試的,學習之餘也寫一寫博客記錄一下。

後面安全題就有點跳出我的知識面了,不過看上去這些題目也挺有趣,好奇能不能刷到滿分,於是趕在 2021年10月30日23:58 分填完了所有網友分享的答案 :)

不知道爲啥,只有 90 分:)

 

 

 

 

本文原文地址: https://www.cnblogs.com/BensonLaur/p/15487884.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章