程序员进阶之算法练习(三十九)Codeforces

正文

1.Drinks Choosing

题目链接
题目大意:
有n个学生,每个学生都有自己喜欢的饮料类型,用整数𝑎1,𝑎2,…,𝑎𝑛 (1≤𝑎𝑖≤𝑘)表示,一共有k种饮料的类型。
现在老师要采购饮料,饮料是两瓶装;
所以老师打算采购(n/2)个单位,保证每个学生至少有一瓶。(n/2向上取整,如果5个人,老师会买3个单位)
老师希望尽可能多的学生能喝到喜欢的饮料类型,问最多能有几个学生喝到自己喜欢的饮料?

输入:
第一行,𝑛 and 𝑘 (1≤𝑛,𝑘≤1000)
接下来n行,分别表示 𝑎1,𝑎2,…,𝑎𝑛 (1≤𝑎𝑖≤𝑘)

输出:
能够喝到喜欢饮料的学生人数;

Examples
input
5 3
1
3
1
1
2
output
4

题目解析:
兴趣相同的,两两成对拿出来,凑成一个单位;(ans += 2)
剩下的所有人(n - ans),每个人的兴趣都不相同,任意两两凑对一个单位;(n-ans+1)/2

    int n, k;
    cin >> n >> k;
    int a[1001] = {0}, ans = 0;
    for (int i = 0; i < n; ++i) {
        int t;
        cin >> t;
        ++a[t];
        if (a[t] % 2 == 0) {
            ans += 2;
        }
    }
    ans += (n - ans + 1) / 2;
    cout << ans << endl;

2.Sport Mafia

题目链接
题目大意:
小明有个糖果盒子,起始的时候是空的。
小明会进行n次操作,每次可以选择:
1、吃掉盒子里的一个糖果;(如果里面有糖果的话)
2、放进去x个糖果,之后x=x+1;(比如这次是放5个,下次就是放6个)
最后盒子里会剩下k个糖果;

例如下面的9个操作:
put 1 candy,
put 2 candies,
eat a candy,
eat a candy,
put 3 candies,
eat a candy,
put 4 candies,
eat a candy,
put 5 candies.

最终会剩下11个糖果。(1+2−1−1+3−1+4−1+5=11)

现在给出操作次数n,还有最终剩下的k个糖果,问小明会吃掉几个糖果。

输入:
第一行,𝑛 and 𝑘 (1≤𝑛≤10^9; 0≤𝑘≤10^9)

输出:
小明吃掉的糖果数;(题目保证数据是有解的)

Examples
input
5 3
1
3
1
1
2
output
4

题目解析:
由题目知道,吃掉的糖果是1、2、3、4、、、,那么假设吃掉的是1~t的糖果。
那么剩下的(n-t)次糖果,肯定是吃糖果的操作。
如果题目有解,那么就有:
总共的放进去糖果数 = 吃糖果数 + 剩下糖果数;
即是:(1+t)*t/2 = (n-t) + k

可以从1开始遍历t,最多重复sqrt(10^9)次就会有解,复杂度可以接受。

    int n, k;
    cin >> n >> k;
    for (int i = 1; i < 100000; ++i) {
        lld sum = (1ll + i) * i / 2;
        if (sum == (k + (n - i))) {
            cout << sum - k << endl;
            return 0;
        }
    }

3.Basketball Exercise

题目链接
题目大意:
篮球教练有2 * n个学生,排成两行,每行有n个人;


每个学生都有一个高度h;(1≤h≤10e9)
现在教练需要选择若干个学生去参加篮球比赛,他决定从左到右选择学生,并且:
1、每列只选择一个学生;
2、不连续选择两个同一行的学生,如果这次选择了第一行的学生,则下次必然选择第二行的学生;

问选择出来的学生高度和最大值是多少;

输入:
第一行,𝑛 (1≤𝑛≤10e5)
第二行,n个整数h,表示第一行学生高度 (1≤ℎ≤10e9)
第三行,n个整数h,表示第二行学生高度 (1≤ℎ≤10e9)

输出:
选择出来的学生高度总和最大值;

Examples
input
5
9 3 5 7 3
5 8 1 4 5
output
29

图中灰色为选中学生

input
3
1 2 9
10 1 1
output
19

图中灰色为选中学生

题目解析:
两个数组,从左到右遍历选择数字,每个index只能选择一个数字,并且两个数组要交替选择。

对于每个数字,只有两种选择:选中或者不选中;
对于每个index,则有三种状态:选择数组a的元素(状态1)、选择数组b的元素(状态2)、都不选择(状态0);
那么有dp[N][i]:
dp[i][0] = max(dp[i-1][0], dp[i-1][1], dp[i-1][2]);
dp[i][1] = max(dp[i-1][2], dp[i-1][0]) + a[i];
dp[i][2] = max(dp[i-1][1], dp[i-1][0]) + b[i];

然后选择dp[N][i]中的最大值即可。


    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    for (int i = 0; i < n; ++i) {
        cin >> b[i];
    }
    
    lld ans = max(a[0], b[0]);
    dp[0][0] = 0;
    dp[0][1] = a[0];
    dp[0][2] = b[0];
    
    for (int i = 1; i < n; ++i) {
        dp[i][0] = max(max(dp[i-1][0], dp[i-1][1]), dp[i-1][2]);
        dp[i][1] = max(dp[i-1][2], dp[i-1][0]) + a[i];
        dp[i][2] = max(dp[i-1][1], dp[i-1][0]) + b[i];
        for (int j = 0; j < 3; ++j) {
            ans = max(ans, dp[i][j]);
        }
    }
    
    cout << ans << endl;

4.Letters Shop

题目链接
题目大意:
有一个小写字母组成的字符串s,长度为n;
有m个人,每个人有一个名字,假如是t[i];
现在小明想知道,对于每个人,至少需要s的前面多少个字符,才能组成他的名字;

假如 𝑠 ="arrayhead",𝑡[𝑖]="arya",那么需要前面5个字符array,才能够组成arya的名字;
假如 𝑠 ="arrayhead",𝑡[𝑖]="areahydra",那么需要前面9个字符arrayhead,才能组成areahydra的名字;

输入:
第一行,整数𝑛,表示字符串长度 (1≤𝑛≤2⋅10^5)
第二行,字符串s;
第三行,整数m,表示m个人; (1≤𝑚≤5⋅10^4)
接下来m行,每行有一个字符串t[i]; (1≤|𝑡[𝑖]|≤2⋅10^5)
题目保证每个人的名字,都可以由字符串s组成,并且m个人的名字总长度不会超过2⋅10^5。

输出:
m行,每行有一个数字,表示需要的最少字符数量。

题目解析:
先不考虑复杂度,直接的做法是将每个人的名字拿出来匹配,一共匹配m次;
怎么匹配比较方便?
把名字统计下,得到b[26],表示26个字符的数量;
然后遍历整个字符串,直到26个字母的数量都满足;
复杂度是O(N),总的复杂度是O(NM);

这个复杂度太高,需要优化。
容易知道,如果前i个字符满足要求,则前i+1个字符也满足要求,那么就可以二分。
同时为了避免多次计算,可以直接换成a[i][j]表示前i个字符,第j个字母的数量。

    int n;
    cin >> n;
    string str;
    cin >> str;
    a[0][str[0] - 'a'] = 1;
    
    for (int i = 1; i < n; ++i) {
        for (int j = 0; j < 26; ++j) {
            a[i][j] = a[i - 1][j];
        }
        ++a[i][str[i] - 'a'];
    }
    
    int m;
    cin >> m;
    while (m--) {
        string t;
        cin >> t;
        int cnt[26] = {0};
        for (int i = 0; i < t.length(); ++i) {
            ++cnt[t[i] - 'a'];
        }
        
        int l = 0, r = n - 1, ans = n - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            
            int ok = 1;
            for (int i = 0; i < 26; ++i) {
                if (cnt[i] && a[mid][i] < cnt[i]) {
                    ok = 0;
                }
            }
            
            if (ok) {
                ans = mid;
                r = mid - 1;
            }
            else {
                l = mid + 1;
            }
        }
        
        cout << ans + 1 << endl;
    }

总结

题目1是贪心,也没有特别的trick;
题目2提供的解法是暴力去枚举,如果操作的次数比较多,比如说n=10e18,此时放入糖果的操作次数会比较多,此时可以使用二分查找;(判断条件是糖果有没有剩余)
题目3是动态规划,状态转移比较简单;样例的数据有点像LIS(最长上升子序列),一开始理解错题意,以为是要求选择出来的人是要身高递减,但是这个题目又不能按照LIS一样做到O(NlogN);
题目4就是典型的二分题目。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容