ABC315 总结 & 题解
Contest Overview
题目质量较高,特别是 F。
建议 D 和 E 对调。
A
Overview
字符串操作题。
Description
给定字符串 s s s,输出删去所有元音字母后的字符串。
Idea
设立一个空字符串 t t t,暴力插入即可。
Solution
部分代码,全部代码见附件。
if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u'){
continue;
}
t = t + s[i];
B
Overview
边界判断可能造成罚时,需注意。
Description
给定 n n n 个月的日历,第 i i i 个月有 t i t_i ti 天(保证总天数为奇),问中间的那一天是几月几号。
Idea
先求出一年有几天, + 1 ÷ 2 +1\div 2 +1÷2,暴力求就可以了。
注意:一月的最后一天不是第二月的第 0 0 0 天。
Solution
部分代码,全部代码见附件。
arrin<int>(d, d + n);
int sum = 0;
repn(i, 0, n, 1) sum += d[i];
sum = (sum + 1) / 2;
int pos = 0;
while(sum - d[pos] > 0){
sum -= d[pos]; pos++;
}
cout << pos + 1 << " " << sum << endl;
C
Overview
套路题,其实没有套路也是可做的。
Description
给定 n n n 个数对,每个数对都有 种类 a a a 和 价值 b b b。
定义一对数对的「价值」是:
- b i + b j b_i+b_j bi+bj, i ≠ j i\ne j i=j
- b i + b j 2 b_i+\frac{b_j}2 bi+2bj, i = j i=j i=j
求出最大价值。
n ≤ 2 × 1 0 5 n \leq 2\times10^5 n≤2×105。
Idea
第二种情况相当好求,这里着重讲第一种情况。
显然,对于每个种类 i i i,最大价值有 这个种类的最大价值 + 其它种类的最大价值。
思考:如何求第二个项?
显然是可以通过拆环 + 线段树做的,但是毕竟是 C,不会这么难。
考虑预处理前缀最大值 p p p,后缀最大值 s s s。
所以答案 = max { p i − 1 , s i + 1 } \max\{p_{i-1},s_{i+1}\} max{pi−1,si+1}。
Solution
部分代码,全部代码见附件。
cn(n); pii p[n];
repn(i, 0, n, 1){
cm(p[i].first); cm(p[i].second);
}
repn(i, 0, n, 1){
if(p[i].second > mx[p[i].first])
mx2[p[i].first] = mx[p[i].first], mx[p[i].first] = p[i].second;
else if(p[i].second > mx2[p[i].first])
mx2[p[i].first] = p[i].second;
}
mmx[1] = mx[1], mmx2[n] = mx[n];
rep(i, 2, n, 1)
mmx[i] = max(mmx[i - 1], mx[i]);
pre(i, n - 1, 1, 1)
mmx2[i] = max(mmx2[i + 1], mx[i]);
int maxv = 0;
rep(i, 1, n, 1){
maxv = max(maxv, max(mx[i] + mx2[i] / 2, mx[i] + max(mmx[i - 1], mmx2[i + 1])));
}
cout << maxv << endl;
D
Overview
中规中矩的一道题,但有些奇怪。
Description
给定一个 h × w h\times w h×w 的矩阵,求不断删去每一个有相同元素的行和有相同元素的列后剩下的个数。
注意:行和列是同时进行的。
h , w ≤ 1000 h,w\leq 1000 h,w≤1000。
Idea
因为本人太菜而先做了 E 和 F,此题只有口胡解法,不保证正确性,欢迎 fake。
考虑到只有 1 0 6 10^6 106 个数,每个数只会被删一次,可以暴力删除。
对于每个行、列维护一个桶和一个 set
。
理论最坏复杂度大约是 O ( 52 n 2 log n ) O(52n^2 \log n) O(52n2logn),但是远远跑不到。可能会卡过去。
E
Overview
板子题。
Description
给定 n n n 个物品和其依赖关系,给出一个能够到达 1 1 1 的排列方式,需要保证选择个数最少。
保证依赖关系组成的图是一个 DAG。
Idea
赤裸裸的板子题。
按照依赖关系建图,拓扑排序就可以了。
怎么保证所用个数最少?
建反向边。DFS 一遍,找到必须选择的点。
Solution
见附件。
F
Overview
好题。较为结论。
Description
给定 n n n 个二维平面上的点。你需要从 1 1 1 一直按顺序跳到 n n n。
你可以选择跳过若干个点。设你跳过了 k k k 个点( 1 1 1 和 n n n 除外),走过的总距离为 x x x。
则你的「罚时」是 x + 2 k − 1 x+2^{k-1} x+2k−1。特别的,我们设 2 − 1 = 0 2^{-1}=0 2−1=0。
n , x i , y i ≤ 1 0 4 n,x_i,y_i \leq 10^4 n,xi,yi≤104,其中 x i x_i xi 和 y i y_i yi 为一个点的坐标。
Idea
注意到总距离最大大约是 1 0 8 10^8 108,所以 k k k 一定 ≤ log 1 0 8 \leq \log 10^8 ≤log108,不然什么也不选就是更优解。
所以只用枚举 1 1 1 到 35 35 35 的 k k k 就可以了(为了防止爆炸我将 k k k 开大了一点)。
剩下的 DP 一下就可以了。
设 d i , j d_{i,j} di,j 为前 i i i 个点跳了 j j j 个点的最小距离。
状态转移方程自己推去!(恼
Solution
部分代码,全部代码见附件。
rep(i, 0, 35, 1){
repn(j, 0, n, 1) rep(k, 0, i, 1){
dp[j][k] = MAXN;
}
dp[0][0] = 0;
repn(j, 1, n, 1) rep(k, 0, i, 1){
rep(l, 0, k, 1){
if(j - l - 1 < 0) break;
dp[j][k] = min(dp[j][k], dp[j - l - 1][k - l] + dist(p[j], p[j - l - 1]));
}
}
ans = min(ans, dp[n - 1][i] + (i == 0 ? 0LL : (1LL << (i - 1LL))));
}