牛客练习赛16 A B C F【思维+图染色+二分+数学公式】

30 篇文章 0 订阅
26 篇文章 0 订阅

A 字典序最大的子序列

链接:https://www.nowcoder.com/acm/contest/84/A
来源:牛客网
题目描述
给定字符串s,s只包含小写字母,请求出字典序最大的子序列。
子序列:https://en.wikipedia.org/wiki/Subsequence
字典序:https://en.wikipedia.org/wiki/Lexicographical_order
输入描述:
一行一个字符串s (1 <= |s| <= 100,000)。
输出描述:
字典序最大的子序列。
示例1
输入
ababba
输出
bbba
示例2
输入
abbcbccacbbcbaaba
输出
cccccbba

分析:直接反向找最大子序列即可;

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int MAXN = 100000 + 10;
char str[MAXN], ch[MAXN], s[MAXN];

int main() {
    scanf("%s", str);
    int len = strlen(str);
    for(int i = 0; i < len; ++i) ch[i] = str[len - i - 1];
    s[0] = ch[0];
    int p = 1;
    char ans = ch[0];
    for(int i = 1; i < len; ++i) {
        if(ch[i] >= ans) {
            s[p++] = ch[i];
            ans = max(ans, ch[i]);
        }
    }
    for(int i = p - 1; i >= 0; i--) {
        printf("%c", s[i]);
    }
    puts("");
    return 0;
}

B 漂亮的树

链接:https://www.nowcoder.com/acm/contest/84/B
来源:牛客网
题目描述
街上有n棵树,标号为1…n,第i棵树的高度为ai。
定义这n棵树是漂亮的,当且仅当
1. 对于所有的i,ai=an-i+1;
2. 对于1 <= i < n / 2 (不是整除),ai + 1= ai + 1;
比如说 “2 3 4 5 5 4 3 2”和“1 2 3 2 1”是漂亮的而“1 3 3 1”和“1 2 3 1”不是。
现在请问最少修改几棵树的高度(可以变大也可以变小),使得这些树是漂亮的。
输入描述:
第一行一个整数n表示树的数量( 1 <= n <= 100,000)。
第二行n个整数表示树的高度( 1 <= ai <= 100,000)。
输出描述:
输出一个整数表示最少修改树的高度的数目。
示例1
输入
3
2 2 2
输出
1
示例2
输入
4
1 2 2 1
输出
0

分析:
哈希差值,先定个基值序列(我假定的是1 2 3…3 2 1),让每位数的值减去对应的基值(注意可能会有负值,加个自定义mod值),最后遍历找出现最多次数的差值,其余根据这个差值进行调整就好了(也就是向这个序列靠拢);

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int MAXN = 1e5 + 10;
int a[MAXN], ma[MAXN << 1];

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        if(i <= (n + 1) / 2) ma[i - a[i] + MAXN]++;
        else ma[n - i + 1 - a[i] + MAXN]++;
    }
    int ans = 0;
    for(int i = 1; i <= MAXN + MAXN; ++i) {
        ans = max(ans, ma[i]);
    }
    printf("%d\n", n - ans);
    return 0;
}

C 任意点

链接:https://www.nowcoder.com/acm/contest/84/C
来源:牛客网
题目描述
平面上有若干个点,从每个点出发,你可以往东南西北任意方向走,直到碰到另一个点,然后才可以改变方向。
请问至少需要加多少个点,使得点对之间互相可以到达。
输入描述:
第一行一个整数n表示点数( 1 <= n <= 100)。
第二行n行,每行两个整数xi, yi表示坐标( 1 <= xi, yi <= 1000)。
y轴正方向为北,x轴正方形为东。
输出描述:
输出一个整数表示最少需要加的点的数目。
示例1
输入
2
2 1
1 2
输出
1
示例2
输入
2
2 1
4 1
输出
0

分析:
我是根据题目条件暴力建个图,然后dfs进行染色,图的个数-1即是结果(好像有简易解法,我写的好像复杂了);
主要我的思路是,遇到和图论有关的题,抽象出一个图的模型,各种数据结构往里面套就行了(有的不会搞。。。)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int MAXN = 100 + 10;
int a[MAXN], b[MAXN], vis[MAXN], col[MAXN];
vector<int> G[MAXN];

inline void dfs(int x) {
    for(int i = 0; i < G[x].size(); ++i) {
        int u = G[x][i];
        if(col[u]) continue;
        col[u] = 1;
        dfs(u);
    }
}
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        scanf("%d %d", &a[i], &b[i]);
    }
    for(int i = 0; i < n; ++i) {
        if(vis[i]) continue;
        for(int j = i + 1; j < n; ++j) {
            if(a[i] == a[j] && b[i] == b[j]) continue;
            if(a[i] == a[j] || b[i] == b[j]) {
                G[i].push_back(j);
                G[j].push_back(i);
                vis[j] == 1;
            }
        }
    }
    int ans = 0;
    for(int i = 0; i < n; ++i) {
        if(col[i]) continue;
        dfs(i);
        ans++;
    }
    printf("%d\n", ans - 1);
    return 0;
}

F 选值

链接:https://www.nowcoder.com/acm/contest/84/F
来源:牛客网
题目描述
给定n个数,从中选出三个数,使得最大的那个减最小的那个的值小于等于d,问有多少种选法。
输入描述:
第一行两个整数n,d(1 <= n <= 100,000,1 <= d <= 1000,000,000);
第二行n个整数满足abs(ai) <= 1,000,000,000。数据保证a单调递增。
输出描述:
输出一个整数表示满足条件的选法。
示例1
输入
4 3
1 2 3 4
输出
4
示例2
输入
4 2
-3 -2 -1 0
输出
2
示例3
输入
5 19
1 10 20 30 50
输出
1

分析:
这个不难,但容易让人跳坑,仔细推公式,不要想当然呀。
二分+数学公式就可以解了,公式就是 n(n+1)/2 n ∗ ( n + 1 ) / 2 ,可以动手模拟一下;

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int MAXN = 1e5 + 10;
LL a[MAXN];

int main() {
    LL n, d;
    scanf("%lld %lld", &n, &d);
    for(LL i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    LL ans = 0;
    for(LL i = 1; i <= n - 2; ++i) {
        LL cnt = a[i] + d;
        LL id = upper_bound(a + 1, a + n + 1, cnt) - (a + 1);
        if(a[id] > cnt) id--;
        LL res = id - i - 1;
        ans = ans + res * (res + 1) / 2;
    }
    printf("%lld\n", ans);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值