CodeCraft-19 and Codeforces Round #537 (Div. 2)解题报告

时间:2019-02-20
本文章向大家介绍CodeCraft-19 and Codeforces Round #537 (Div. 2)解题报告,主要包括CodeCraft-19 and Codeforces Round #537 (Div. 2)解题报告使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Codeforces Round #537 (Div. 2) 题解报告

A. Superhero Transformation

题意

问能否通过把辅音字母换成另一个辅音字母,元音字母换成另一个元音字母使得两个字符串相同。

题解

按题意模拟。

代码

#include<bits/stdc++.h>
const int N = 1e3 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
char s[N], t[N]; int n, m;
bool ok[N];
int main() {
	ok['a'] = true;
	ok['e'] = true;
	ok['i'] = true;
	ok['o'] = true;
	ok['u'] = true;
	scanf("%s", &s); int n = strlen(s);
	scanf("%s", &t); int m = strlen(t);
	if(n != m) return puts("No"), 0;
	for(int i = 0;i < n; ++i)
		if(ok[s[i]] != ok[t[i]]) 
			return puts("No"), 0;
	puts("Yes");
	return 0;
}

B. Average Superhero Gang Power

题意

给一个序列,你可以操作mm次,每次可以去掉某个数或者将某个数+1,后者每个数不能做超过kk次。最大化平均值。

题解

FST差评,pretest实在太弱,和我一样。
考试的是时候随便贪心了一下,大概就是先一直删然后再大分类,结果发现自己zz了。
实际上枚举删除几个数,贪心地删掉小的那些即可。

代码

#include<bits/stdc++.h>
const int N = 1e5 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int n, k, m, a[N];
long long sum, mx;
int main() {
	n = ri(); k = ri(); m = ri();
	for(int i = 1;i <= n; ++i)
		a[i] = ri(), sum += a[i];
	std::sort(a + 1, a + n + 1);
	double mx = 0;
	for(int i = 0;i <= std::min(n - 1, m); ++i) {
		sum -= a[i];
		mx = std::max(mx, (double)(sum + std::min((long long)m - i, 1LL * k * (n - i))) / (double)(n - i));
	}
	printf("%.10lf\n", mx);
	return 0;
}

C. Creative Snap

题意

给一个长度为2n2^n的基地,在a1aka_1\cdots a_k位置有“复仇者”,你要烧掉整个基地,每次你要么分成两半分别烧,要么直接烧。如果直接烧,没人的话花费AA,有人的话花费BnalB\cdot n_a \cdot lnan_a是人数,ll是长度。A,BA,B是给定的常数,问最小花费。

题解

如果nn小一点的花可以直接分治对吧。
某段pp的代价f(p)f(p)就是f(p)=min{f(ls)+f(rs),[cnt[p]=0]A+[cnt[p]0]Bcnt[p]l}f(p)=\min \{f(ls) +f(rs),[cnt[p]= 0]\cdot A + [cnt[p]\neq0]\cdot B\cdot cnt[p] \cdot l\}cnt[p]cnt[p]是人数ls,rsls,rs是左右子区间。
然后把整个分治结构看成一颗线段树,那么计算f(p)f(p)相当于是在用左右子树更新当前子树。
动态开点即可。

代码

#include<bits/stdc++.h>
const int M = 31e5 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int cnt[M], ls[M], rs[M], A, B, n, k, sz, rt;
long long f[M];
void Ins(int &p, int L, int R, int x) {
	if(!p) p = ++sz; ++cnt[p];
	if(L == R) return f[p] = 1LL * B * cnt[p], void();
	int m = L + R >> 1;
	if(x <= m) Ins(ls[p], L, m, x);
	else Ins(rs[p], m + 1, R, x);
	f[p] = std::min(1LL * B * cnt[p] * (R - L + 1), f[ls[p]] + f[rs[p]]);
}
int main() {
	n = ri(); k = ri(); A = ri(); B = ri();
	f[0] = A; int all = 1 << n;
	for(int i = 1;i <= k; ++i)
		Ins(rt, 1, all, ri());
	printf("%lld\n", f[rt]);
	return 0;
}

D. Destroy the Colony

题意

有一个由大写字母和小写字母组成的长度为偶数一个字符串,将这个字符串重排列,使得重排列以后把字符串劈成两半,任何相同的字符都同一半的位置上,同时满足原字符串xxyy两种字符也在同一半上。多组询问。

题解

这题差一点点想出来了。如果不是T2FSTT2FSTT4T4没想出来的话,我现在可能已经橙了TT。
显然本质不同的询问只有C522=1326C_{52}^2=1326种。
考虑如果我们已经决定了每种字符归属哪边,那么方案数就是将两边重排列的方案数的乘积,也就是
(n2)!cnt1[i](n2)!cnt2[i]=((n2)!)2cnt[i]\frac{(\frac{n}{2})!}{\prod cnt_1[i]} \cdot \frac{(\frac{n}{2})!}{\prod cnt_2[i]}=\frac{((\frac{n}{2})!)^2}{\prod cnt[i]}
其中必须满足cnt1[i]=n2\sum cnt_1[i]=\frac{n}{2}