牛客练习赛16

比赛链接

A 字典序最大的子序列

题意就是题目意思,这里贪心的先把最大的字符选为第一个,接着是次大的。

然后这样会有个问题,子序列虽然不要求连续,但是要求按顺序,

所以可以设一个数组a[],a[i]表示i~n间最大的字符,这样就保证贪心不会出问题

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2 * (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
char str[maxn];
char ans[maxn];
int maxp[maxn];
int main() {
    while (~scanf("%s", str)) {
        memset(maxp, 0, sizeof(maxp));
        int len = strlen(str);
        maxp[len - 1] = str[len - 1];
        for (int i = len - 2; i >= 0; i--) {
            int tmp = str[i];
            maxp[i] = max(maxp[i + 1], tmp);
        }
        int cnt = 0;
        memset(ans, 0, sizeof(ans));
        for (int i = 0; i < len; i++) {
            int tmp = str[i];
            if (tmp == maxp[i]) {
                ans[cnt++] = str[i];
            }
        }
        printf("%s\n", ans);
    }
    return 0;
}

B 漂亮的树

给出一些树的高度,问最少修改多少颗树能使这n颗树形成屋顶状(等腰三角形,差值为1)

笔者读的时候脑子抽了想到去算需要修最少的长度了

要尽量少修的话,显然就是找出去掉阶梯性质之后的最多有多少颗树是等高的,也就是把这个形状拍扁。

因为数值有点多所以map哈希吧

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int a[maxn];
int main() {
	int n;
	while (~scanf("%d", &n)) {
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]);
		int m = (n + 1) / 2;
		for (int i = 0; i < m; i++)
			a[i] -= i;
		for (int i = m; i < n; i++)
			a[i] -= n - i - 1;
		mapmp;
		for (int i = 0; i < n; i++)
			mp[a[i]]++;
		int ans = 0;
		for (map::iterator it = mp.begin(); it != mp.end(); ++it)
			ans = max(ans, it->second);
		printf("%d\n", n - ans);
	}
	return 0;
}

C 任意点

对于一些点,如果他们能通过规则连在一起,把他们归到一个点集,

对于两个不能连在一起的点集,根据规则显然只需要再加一个点就能把这两个点集连起来

所以先把所有点归并集合然后算集合数-1就是答案

这里用并查集吧

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int pre[maxn];
struct nodes {
	bool visx[1111], visy[1111];
}a[111];
void init(int n) {
	for (int i = 0; i <= n; i++) {
		pre[i] = i;
		memset(a[i].visx, 0, sizeof(a[i].visx));
		memset(a[i].visy, 0, sizeof(a[i].visy));
	}
}
int find(int x) {
	if (x == pre[x]) return x;
	return pre[x] = find(pre[x]);
}
void unites(int x, int y) {
	x = find(x), y = find(y);
	if (x == y) return;
	else if (x > y) pre[x] = y;
	else pre[y] = x;
}
int main() {
	int n;
	while (~scanf("%d", &n)) {
		int x, y;
		init(n);
		for (int i = 0; i < n; i++) {
			scanf("%d%d", &x, &y);
			for (int j = 0; j < i; j++) {
				if (a[j].visx[x] || a[j].visy[y])
					unites(i, j);
			}
			a[i].visx[x] = a[i].visy[y] = 1;
		}
		int ans = 0;
		for (int i = 0; i < n; i++)
			if (i == find(i))
				ans++;
		printf("%d\n", ans - 1);
	}
	return 0;
}

D k进制数

待补

E 求值

把或的结果丢到set里不断算就行了,因为set内的元素不重复所以实际运算量不会很大

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 4 * (int)(1e6) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
bool vis[maxn];
set s[3];
int main(){
    int n, cur = 0, x;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &x);
        cur ^= 1;
        s[cur].clear();
        for (auto &it : s[cur ^ 1]) {
            int tmp = x | it;
            vis[tmp] = 1;
            s[cur].insert(tmp);
        }
        vis[x] = 1;
        s[cur].insert(x);
    }
    int ans = 0;
    for (int i = 0; i < maxn; i++)
        if (vis[i])
            ans++;
    printf("%d\n", ans);
    return 0;
}

F 选值

题目意思得 a[j]-a[i]<=d,转化过来就是a[i]>=a[j]-d

这样的话只要用二分查找到a[i],然后在i~j-1中选两个数就是符合题目的组合.

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2 * (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
LL a[maxn];
int main() {
	int n;
	LL d;
	while (~scanf("%d%lld", &n, &d)) {
		for (int i = 0; i < n; i++)
			scanf("%lld", &a[i]);
		LL ans = 0;
		for (int i = n - 1; i >= 0; i--) {
			int pos = lower_bound(a, a + n, a[i] - d) - a;
			ans += LL(i - pos)*LL(i - pos - 1) / 2;
		}
		printf("%lld\n", ans);
	}
	return 0;
}

你可能感兴趣的:(acm,牛客网)