牛客练习赛16 ACF

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

最后一个字符一定在,所以从后面找,单调递增的。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1e5+10;
 4 char str[N], str1[N];
 5 int main() {
 6     cin >> str;
 7     int ans = 0;
 8     char MAX = 'a';
 9     for(int len = strlen(str)-1; len >= 0; len--) {
10         if(str[len] >= MAX) {
11             MAX = str[len];
12             str1[ans++] = str[len];
13         }
14     }
15     for(int i = ans-1; i >= 0; i --) {
16         printf("%c",str1[i]);
17     }
18     printf("\n");
19     return 0;
20 }

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

并查集问题,当有两个点可以通时就合并,最后看有几个集合,减1就是答案了。
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 110;
 4 int fa[N];
 5 struct Nod{
 6     bool visx[N*10], visy[10*N];
 7     Nod() {
 8         memset(visx, 0, sizeof(visx));
 9         memset(visy, 0, sizeof(visy));
10     }
11 }nod[N];
12 int find(int x) {
13     return fa[x] == x ? x: find(fa[x]);
14 }
15 void unit(int x, int y) {
16     x = find(x), y = find(y);
17     if(x > y) fa[x] = y;
18     else fa[y] = x;
19 }
20 int main() {
21     int n, ans = 0, x, y;
22     for(int i = 0; i <= 100; i ++) fa[i] = i;
23     cin >> n;
24     for(int i = 0; i < n; i ++) {
25         cin >> x >> y;
26         for(int j = 0; j < i; j ++) {
27             if(nod[j].visx[x] || nod[j].visy[y]) unit(i,j);
28         }
29         nod[i].visx[x] = true;
30         nod[i].visy[y] = true;
31     }
32     for(int i = 0; i < n; i ++) {
33         if(i == find(i)) ans++;
34     }
35     cout << ans - 1 << endl;
36     return 0;
37 }

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-2个遍历,找到所以小于等于ai+d的数量cnt,cnt*(cnt-1)/2 就是选择 ai 时有多少种。

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N = 1e5+10;
 5 ll a[N];
 6 int main() {
 7     ll n, d;
 8     scanf("%lld%lld",&n,&d);
 9     for(int i = 0; i < n; i ++) scanf("%lld",&a[i]);
10     a[n] = 1e10;
11     ll ans = 0;
12     for(int i = 0; i < n-2; i ++) {
13         ll tmp = a[i] + d;
14         int index = upper_bound(a,a+n,tmp) - a -1;
15         // cout << index << endl;
16         ll cnt = index - i;
17         if(cnt > 1) {
18             ans += (cnt-1)*cnt/2;
19         }
20     }
21     cout << ans << endl;
22     return 0;
23 }

猜你喜欢

转载自www.cnblogs.com/xingkongyihao/p/8964447.html