Educational Codeforces Round 127 VP 记录
妈的最近手感烂到家了……这场 VP 连 D 都没切……
A. String Building
看一下有没有单独的 \(a\) 或者 \(b\) 就好了。
B. Consecutive Points Segment
稍微分讨一下,大约有一下无解情况:
- 存在差值 \(>3\)。
- 存在至少 \(2\) 个位置差值 \(=3\) 。
- 存在至少 \(3\) 个位置差值 \(=2\)。
- 同时存在某个位置差值 \(=2\) 和 \(=3\)。
void Main() {
n = read();
for(int i = 1; i <= n; ++i) a[i] = read();
int cnt2 = 0, cnt3 = 0;
for(int i = 2; i <= n; ++i) {
if(a[i] - a[i - 1] > 3) return puts("NO"), void();
else if(a[i] - a[i - 1] == 3) cnt3 ++;
else if(a[i] - a[i - 1] == 2) cnt2 ++;
}
if(cnt2 > 2 || cnt3) return puts("NO"), void();
if(cnt3 >= 2) return puts("NO"), void();
puts("YES");
return ;
}
signed main() {
T = read();
while(T--) Main();
return 0;
}
C. Dolce Vita
考虑模拟。
先看看第一天能买多少,最优的情况肯定是买若干个最便宜的,然后看看第二天如果不能买第一天同样的量,肯定要减去若干个此时售价最大的糖。以此类推直到一个都买不了。
发现有连续的很多天买的量是相同的,可以直接算一下有多少天来加速模拟。
然后做完了。
int F(int x) { return sum + (x - 1) * now; }
void Main() {
n = read(), K = read(), ans = 0; // 答案
for(int i = 1; i <= n; ++i) a[i] = read();
sort(a + 1, a + n + 1);
sum = 0, cnt = 0; // 日花费 和 天数
now = 0; // 能买几家
while(now < n && sum + a[now + 1] <= K) sum += a[now + 1], ++now; // 第一天使劲买买买
while(now) {
int res = (K - sum) / now + 1;
ans += res * now;
cnt += res;
sum += res * now;
while(sum > K) {
sum = sum - cnt - a[now];
--now;
}
}
cout << ans << "\n";
}
signed main() {
T = read();
while(T--) Main();
return 0;
}
D. Insert a Progression
D WA 2,调出来再说。吐了,是因为一个小细节……
思路就是,你先手玩一下,你发现加入这些数只可能让答案变劣,那就考虑怎么让答案不至于更劣。
设 \(p,q\) 分别是 \(\max \{a_i\}\) 和 \(\min \{a_i\}\) ,那么对于在 \(p,q\) 之间的 \(x\),一定能找到一个 \(a \le x \le b\) 的位置插进去。造成的贡献为 \(0\)。
那考虑 \([1,p)\) 和 \((q,k]\) 这段区间的贡献(设 \(k\) 是要插入的最大的数)
首先这段区间的数肯定要放在一起,然后考虑放在哪个位置,注意放在中间与放在两边不同的是多出来的部分有一个两倍的贡献。
然后把 \([1,p)\) 在每个位置的贡献拿出来扔进一个堆里,把 \((q,k]\) 在每个位置的贡献拿出来仍进一个堆里。
从两个堆里分别取一个不同位置的最小值即可。
当然有一种更简单的方式是去分析在中间会放在哪里,\([1,p)\) 肯定放在 \(p\) 的左侧或者右侧,\((q,k]\) 这段肯定放在 \(q\) 的左侧或者右侧,然后和把他们放在两边的贡献取个 \(\min\) 加起来就好了。
我写的堆,所以代码比其他人多了 1k ……
讨论的写法可以去看何老师的 [link](Submission #154803256 - Codeforces)
#include<bits/stdc++.h>
#define LL long long
#define int long long
#define orz cout << "tyy YYDS!!!\n"
using namespace std;
const int MAXN = 2e5 + 10;
const int INF = 1e9 + 7;
const int mod = 998244353;
struct node {
int val, pos;
bool operator < (const node &b) const {
return val > b.val;
}
};
int T, n, K;
int a[MAXN];
bool vis[MAXN];
priority_queue<node> q1, q2;
int read() {
int s = 0, f = 0; char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void Main() {
n = read(), K = read();
int ans = 0;
for(int i = 1; i <= n; ++i) a[i] = read();
for(int i = 2; i <= n; ++i) ans += abs(a[i] - a[i - 1]);
int Max = a[1], Min = a[1];
for(int i = 1; i <= n; ++i) {
Max = max(Max, a[i]);
Min = min(Min, a[i]);
}
for(int i = 1; i <= n + 1; ++i) vis[i] = false;
while(!q1.empty()) q1.pop();
while(!q2.empty()) q2.pop();
q1.push((node){abs(a[1] - 1), 1}), q1.push((node){abs(a[n] - 1), n + 1});
q2.push((node){abs(a[1] - K), 1}), q2.push((node){abs(a[n] - K), n + 1});
for(int i = 2; i <= n; ++i) {
int tmp;
tmp = min(a[i - 1], a[i]);
q1.push((node){2 * abs(tmp - 1), i});
tmp = max(a[i - 1], a[i]);
q2.push((node){2 * abs(tmp - K), i});
}
int res1 = 0, res2 = 0;
if(1 < Min) {
vis[q1.top().pos] = true;
res1 += q1.top().val;
}
if(K > Max) {
if(vis[q2.top().pos]) {
node u = q2.top(); q2.pop();
res1 += q2.top().val;
q2.push(u);
} else {
res1 += q2.top().val;
}
}
vis[q1.top().pos] = false;
if(K > Max) {
vis[q2.top().pos] = true;
res2 += q2.top().val;
}
if(1 < Min) {
if(vis[q1.top().pos]) {
node u = q1.top(); q1.pop();
res2 += q1.top().val;
q1.push(u);
} else {
res2 += q1.top().val;
}
}
vis[q2.top().pos] = false;
// cout << "see: " << ans << " " << res1 << " " << res2 << "\n";
// cout << "see: " << q1.top().val << " " << q2.top().val << "\n";
cout << ans + min(res1, res2) << "\n";
}
signed main() {
T = read();
while(T--) Main();
return 0;
}