2018年全国多校算法寒假训练营练习比赛(第二场)

A 吐泡泡

链接:https://www.nowcoder.com/acm/contest/74/A
来源:牛客网
题目描述
小鱼儿吐泡泡,嘟嘟嘟冒出来。小鱼儿会吐出两种泡泡:大泡泡”O”,小泡泡”o”。
两个相邻的小泡泡会融成一个大泡泡,两个相邻的大泡泡会爆掉。
(是的你没看错,小气泡和大气泡不会产生任何变化的,原因我也不知道。)
例如:ooOOoooO经过一段时间以后会变成oO。
输入描述:
数据有多组,处理到文件结束。
每组输入包含一行仅有’O’与’o’组成的字符串。
输出描述:
每组输出仅包含一行,输出一行字符串代表小鱼儿吐出的泡泡经过融合以后所剩余的泡泡。
示例1
输入
ooOOoooO
输出
oO
说明
自左到右进行合并
备注:
对于100%的数据,
字符串的长度不超过100。

分析:
注意题意,泡泡的结合仅一个过程自左向右,一个栈的操作就可以了,写栈时一定注意栈空状态。。。

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;
typedef long long LL;

const int mod = 24 * 60;
const int MAXN = 1e2 + 10;
char str[MAXN], ch[MAXN];

int main() {
    while(~scanf("%s", str)) {
        int p = 0, len = strlen(str);
        str[len] = 0;
        stack<char> s;
        for(int i = 0; i < len; i++) {
            if(str[i] == 'o') {
                if(s.empty()) s.push('o');
                else if(s.top() == 'o') {
                    s.pop();
                    if(s.empty()) s.push('O'); //注意所有的栈空状态
                    else if(s.top() == 'O') s.pop();
                    else s.push('O');
                }
                else s.push('o');
            }
            else {
                if(s.empty()) s.push('O');
                else if(s.top() == 'O') s.pop();
                else s.push('O');
            }
        }
        while(!s.empty()) {
            ch[p++] = s.top();
            s.pop();
        }
        for(int i = p - 1; i >= 0; i--) {
            printf("%c", ch[i]);
        }
        printf("\n");
    }
    return 0;
 }

B TaoTao要吃鸡

链接:https://www.nowcoder.com/acm/contest/74/B
来源:牛客网
题目描述
Taotao的电脑带不动绝地求生,所以taotao只能去玩pc版的荒野行动了,
和绝地求生一样,游戏人物本身可以携带一定重量m的物品,装备背包
之后可以多携带h(h为0代表没有装备背包)重量的东西。玩了几天
taotao发现了一个BUG,当装备背包之后,如果可携带重量没有满,就
可以拿一个任意重的东西。(解释看样例)有一天taotao空降到了一个
奇怪的岛上,岛上有n件装备,每个装备都有重量Wi和威力值Vi,但taotao
不认识这些装备,所以他来求助你,挑选威力最大的装备,帮助他吃鸡。
输入描述:
本题有多组输入(小于10),当n=0时结束输入。
第一行输入n,m,h。n,m,h为整数,并且0<=n,m,h<=100,
接下来n行,每行输入第i个物品的物品的重量Wi和威力值Vi。0<=Wi,Vi<=100.
输出描述:
输出最大威力值,每组输出一行。
示例1
输入
3 3 3
2 3
3 2
2 3
0
输出
8
说明
可携带的总重量为6,当拿了前两件装备,此时容量为5/6,还可以再拿第三件物品。

分析:
注意读题,当有 h!=0 h ! = 0 的时候,才会出现bug。数据范围很小,xjb搞就行。可以枚举不拿的那一件物品,其余的用01背包处理,就可以了。
我试了一下把最大vi的物品贪心出来,尽然过了,数据好水。。。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;

typedef long long LL;
const int MAXN = 110;
int w[MAXN], v[MAXN], dp[MAXN << 2];

int main() {
    int n, m, h;
    while(scanf("%d", &n) && n) {
        scanf("%d %d", &m, &h);
        m += h;
        for(int i = 0; i < n; i++) {
            scanf("%d %d", &w[i], &v[i]);
        }
        int ans = 0;
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; i++) {
            for(int j = m; j >= w[i]; j--) {
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
                ans = max(ans, dp[j]);
            }
        }
        if(!h) {
            printf("%d\n", ans);
            continue;
        }
        for(int p = 0; p < n; p++) { //枚举不能拿的每一件物品
            memset(dp, 0, sizeof(dp));
            for(int i = 0; i < n; i++) {
                if(i == p) continue;
                for(int j = m; j >= w[i]; j--) {
                    dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
                }
            }
            int cnt = dp[m];
            for(int i = 0; i < m; i++) {
                cnt = max(cnt, dp[i] + v[p]);
            }
            ans = max(ans, cnt);
        }
        printf("%d\n", ans);
    }
}

贪心写法,数据水,是可以hack掉的。。。
2 2 2
5 1
2 3
输出:4

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;

typedef long long LL;
const int MAXN = 110;
int w[MAXN], v[MAXN], dp[MAXN << 2];

int main() {
    int n, m, h;
    while(scanf("%d", &n) && n) {
        memset(dp, 0, sizeof(dp));
        scanf("%d %d", &m, &h);
        m += h;
        int ans = 0, res = 1e6, id, ant = 0;
        for(int i = 0; i < n; i++) {
            scanf("%d %d", &w[i], &v[i]);
            if(v[i] >= ant) { //贪心最大vi
                ant = v[i];
                if(w[i] < res) {
                    id = i;
                }
            }
        }
        for(int i = 0; i < n; i++) {
            for(int j = m; j >= w[i]; j--) {
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
                ans = max(ans, dp[j]);
            }
        }
        if(!h) {
            printf("%d\n", ans);
            continue;
        }
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; i++) {
            if(i == id) continue;
            for(int j = m; j >= w[i]; j--) {
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
            }
        }
        int cnt = max(dp[m], ans);
        for(int i = 0; i < m; i++) {
            cnt = max(cnt, dp[i] + ant);
        }
        printf("%d\n", cnt);
    }
}

D YB要打炉石

链接:https://www.nowcoder.com/acm/contest/74/D
来源:牛客网
题目描述
Wozuinb非常喜欢打炉石传说,但是菜的不行,所以他决定打
竞技场来练练手。系统按顺序给出n张卡牌,每张卡牌都有自
己的使用消耗a[i],每次只给出一张,wozuinb可以选择或者
弃掉这张牌。每选择一张牌都会按选择顺序放在卡槽中,当
卡槽中放满30张即可组成一套套牌。Wozuinb希望自己的套牌的
消耗满足一个平滑的曲线,即30张卡牌都满足第i张卡牌的消耗
不小于第i-1张(i>1)。请你帮助wozuinb看一看,这些卡牌能不
能组成想要的套牌,如果能组成输出“yes”,如果不能输出“no”。
输入描述:
第一行输入一个整数n, 0<n<100 0 < n < 100
第二行输入一行数字a[i],每个数字用空格隔开,代表第i张出现的卡牌的消耗。
输出描述:
输出一行,“yes”或“no”
示例1
输入
5
1 2 3 4 5
输出
no

分析
非严格最长递增子序列,O(nlogn)过的;

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;
typedef long long LL;

const int mod = 24 * 60;
const int MAXN = 1e2 + 10;
int dp[MAXN], arr[MAXN];

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &arr[i]);
    }
    dp[1] = arr[1];
    int p = 2;
    for(int i = 2; i <= n; i++) {
        int id = upper_bound(dp + 1, dp + p, arr[i]) - dp;
        if(id == p || arr[i] >= dp[p - 1]) dp[p++] = arr[i];
        else {
            dp[id] = arr[i];
        }
    }
    if(p > 30) puts("yes");
    else puts("no");
    return 0;
 }

/*
30
2 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
*/

E 小G有一个大树

链接:https://www.nowcoder.com/acm/contest/74/E
来源:牛客网
题目描述
小G想要把自己家院子里的橘子树搬到家门口(QAQ。。就当小G是大力水手吧)
可是小G是个平衡性灰常灰常差的人,他想找到一个这个橘子树的平衡点。
怎么描述这棵树呢。。。就把它看成由一个个节点构成的树吧。结点数就
代表树重。
输入描述:
多组数据输入输出,
第一行包含一个整数n(3<=n<=1000)代表树的结点的个数
以下n-1行描述(1-n)节点间的连接关系。
输出描述:
输出两个个整数 x,num 分别代表树的平衡点,和删除平衡点后最大子树的结点数(如果结点数相同输出编号小的)。
示例1
输入
3
1 2
1 3
输出
1 1

分析:
裸的树重心,直接暴力,没用树形dp;

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;

const int MAXN = 1010;
int dp[MAXN][MAXN];
vector<int> G[MAXN];
int ans, n, x, y;

inline void init() {
    for(int i = 0; i < MAXN; i++) {
        G[i].clear();
    }
}

inline void dfs(int u, int cnt) {
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(v == cnt) continue;
        ans++;
        dfs(v, u);
    }
}

int main() {
    while(scanf("%d", &n) != EOF) {
        init();
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        int sum1 = MAXN, sum2 = MAXN * MAXN; //节点和编号
        for(int i = 1; i <= n; i++) {
            int cnt1 = 0;
            for(int j = 0; j < G[i].size(); j++) {
                ans = 1;
                dfs(G[i][j], i);
                cnt1 = max(cnt1, ans);
            }
            if(sum1 > cnt1) {
                sum1 = cnt1;
                sum2 = i;
            }
        }
        printf("%d %d\n", sum2, sum1);
    }
    return 0;
}

F 德玛西亚万岁

链接:https://www.nowcoder.com/acm/contest/74/F
来源:牛客网
题目描述
德玛西亚是一个实力雄厚、奉公守法的国家,有着功勋卓著的光荣军史。
这里非常重视正义、荣耀、职责的意识形态,这里的人民为此感到强烈自豪。
有一天他们想去制裁邪恶的比尔吉沃特,于是派遣了自己最优秀的战士。
结果比尔吉沃特领土太小,只有长为n宽为m共计n*m块土地,其中有些土
地标记为0表示为高山峻岭或者深海湖泊,英雄们无法在其中站立,只有标
记为1的土地才能容纳一个英雄。德玛西亚的英雄们战斗时有一个特点,他
们不希望队友站在自己旁边显得很暧昧。请问最多能有多少种安排德玛西
亚英雄的方法?
输入描述:
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 12, m <= 12 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的比尔吉沃特领土。
输出描述:
输出一个整数n代表安排应用的方法。
(答案取膜100000000)
示例1
输入
3 3
1 1 1
0 1 1
1 0 0
输出
24

分析:
dp[i][j]ijdp[p][i]=dp[p][i]+dp[j][i1] d p [ i ] [ j ] : 第 i 种 状 态 在 第 j 行 的 方 案 数 , d p [ p ] [ i ] = d p [ p ] [ i ] + d p [ j ] [ i − 1 ]
vis[i]i v i s [ i ] : 表 示 第 i 种 的 状 态 ;
把满足的状态先预处理状压出来,把网格可填的位置二进制表示,然后把这些状态按行填进去,和可填的二进制再进行与运算。初始化第一行,然后暴力第 i i 行和第i1行状态,O( 22412 2 24 ∗ 12 ) ;

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;

const int mod = 1e8;
const int MAXN = 15;
int arr[MAXN], dp[2 << 13][MAXN], vis[2 << 13];

inline void dfs_DP(int &res, int m) {
    for(int i = 0; i < (1 << m); i++) {
        if((i & (i << 1)) == 0) {
            vis[res++] = i;
        }
    }
}

int main() {
    int n, m;
    while(scanf("%d %d", &n, &m) != EOF) {
        memset(dp, 0, sizeof(dp));
        memset(arr, 0, sizeof(arr));
        memset(vis, 0, sizeof(vis));
        int k, ans = 1;
        dfs_DP(ans, m);
       // printf("%d -> %d\n", ans, m);
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < m; j++) {
                scanf("%d", &k);
                if(!k) arr[i] += (1 << j);
            }
        }
        for(int i = 1; i < ans; i++) {
            if((arr[1] & vis[i]) == 0) {
                dp[i][1] = 1;
            }
        }
        for(int i = 2; i <= n; i++) {
            for(int j = 1; j < ans; j++) {
                for(int p = 1; p < ans; p++) {
                    int x = vis[j], y = vis[p];
                    if((x & y) || (y & arr[i])) continue;
                    dp[p][i] = (dp[p][i] + dp[j][i - 1]) % mod;
                }
            }
        }
        int sum = 0;
        for(int i = 1; i < ans; i++) {
            sum = (sum + dp[i][n]) % mod;
        }
        printf("%d\n", sum % mod);
    }
}

G 送分了QAQ

链接:https://www.nowcoder.com/acm/contest/74/G
来源:牛客网
题目描述
杭州人称傻乎乎的人为62,而嘟嘟家这里没有这样的习俗。
相比62,他那里的人更加讨厌数字38,当然啦,还有4这个
数字!所以啊,嘟嘟不点都不想见到包含38或者4的数字。
每次给出一个区间[n,m],你能找到所有令人讨厌的数字吗?
输入描述:
多组输入输出;
输入的都是整数对n、m 0<nm<1000000 ( 0 < n ≤ m < 1000000 )
如果遇到都是0的整数对,则输入结束。
输出描述:
对于每次的输入
输出全部令人讨厌的数的个数
示例1
输入
1 100
0 0
输出
20

分析:
预处理区间和,或者数位dp解;

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;

const int mod = 24 * 60;
const int MAXN = 1e6 + 10;
int dp[MAXN];

bool judge(int x) {
    int ans = x, p = 0;
    int arr[10];
    while(ans) {
        arr[p++] = ans % 10;
        ans /= 10;
    }
    arr[p] = 0;
    for(int i = 0; i < p; i++) {
        if(arr[i] == 8 && arr[i + 1] == 3 || arr[i] == 4) return false;
    }
    return true;
}

void init() {
    dp[0] = 0;
    for(int i = 1; i <= MAXN - 5; i++) {
        dp[i] += dp[i - 1];
        if(!judge(i)) dp[i] += 1;
    }
}

int main() {
    int n, m;
    init();
    while(scanf("%d%d", &n, &m) && (n + m)) {
        printf("%d\n", dp[m] - dp[n - 1]);
    }
    return 0;
 }

H 了断局

链接:https://www.nowcoder.com/acm/contest/74/H
来源:牛客网
题目描述
既然是了断局了,大家就随便玩玩数字呗。
已知一个数列前10项分别是
{0, 1, 1, 2, 4, 7, 13, 24, 44, 81}
小G不满足呀:我要更多的数!!!不给就不让你们玩了。
小G会问你第n项是什么数字,请回答这个顽皮的孩子吧。
输入描述:
多组数据输入输出;
第一行输入一个整数n(1<=n<=50)
输出描述:
输出数列中的第n个数。
示例1
输入
1
2
3
输出
0
1
1

分析:
初项题目中给出,一眼递推式: dp[i]=dp[i1]+dp[i2]+dp[i3] d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] + d p [ i − 3 ] ;

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;

const int mod = 24 * 60;
const int MAXN = 1e6 + 10;
LL dp[55];

void init() {
    dp[0] = 0;
    dp[1] = dp[2] = 1;
    for(int i = 3; i <= 50; i++) {
        dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
    }
}

int main() {
    int n;
    init();
    while(scanf("%d", &n) != EOF) {
        printf("%lld\n", dp[n - 1]);
    }
    return 0;
 }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值