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

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