一万四参赛,VP赛时60
A. Max Plus Size
一定选择最大值,若有多个最大值,优先选在奇数位置的最大值,后间隔涂上红色。
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int T, n, a[N];
int main() {
scanf("%d", &T);
while(T --) {
scanf("%d", &n);
int mx = 0;
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]), mx = max(mx, a[i]);
if(n & 1) {
int flag = 0;
for(int i = 1; i <= n; i ++)
if(mx == a[i] && (i & 1)) flag = true;
printf("%d\n", mx + n / 2 + flag);
}
else printf("%d\n", mx + n / 2);
}
return 0;
}
B. All Pairs Segments
对于相邻两个数之间的区间,所有数被覆盖次数相同,且与左右节点数相关,列式子计算即可。
用 map[x] 记录恰好被 x 条线段覆盖的数的数量。
针对询问输出即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int T, n, m, a[N];
int main() {
scanf("%d", &T);
while(T --) {
map<long long, int> mp;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 2; i <= n; i ++) {
long long s = 1ll * (i - 1) * (n - i + 1);
mp[s] += a[i] - a[i - 1] - 1;
}
for(int i = 1; i <= n; i ++) {
long long s = 1ll * (i - 1) * (n - i);
s += n - 1;
mp[s] += 1;
}
while(m --) {
long long k;
scanf("%lld", &k);
printf("%d ", mp[k]);
}
printf("\n");
}
return 0;
}
C. Cards Partition
每个抽屉里面不能有相同的卡片,因此每个抽屉最多 n 张卡片。另一方面,最少得有 max(a[i]) 个抽屉。
当 k 较大时,直接输出 min{n, sum / max(a[i])} 。
当 k 较小时,从 sum / max(a[i]) 开始枚举每个抽屉中卡片的数量。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
long long T, n, k, a[N];
int main() {
scanf("%lld", &T);
while(T --) {
scanf("%lld%lld", &n, &k);
long long sum = 0, mx = 0;
for(int i = 1; i <= n; i ++)
scanf("%lld", &a[i]), sum += a[i], mx = max(a[i], mx);
if(sum / mx != (sum + k) / mx)
printf("%d\n", min((sum + k) / mx, n));
else {
for(int i = sum / mx; i >= 1; i --) {
int t = sum % i;
if(t == 0) t = i;
if(i - t <= k) {
printf("%d\n", i);
break;
}
}
}
}
return 0;
}
D. Speedbreaker
显然,征服区间时刻是连续。
对于每一时间点 i ,找到最左端小于等于 i 的 a[l] ,最右端小于等于 i 的 a[r] 。在 i 时刻 [l,r] 内城市都得被征服。
因此出发点只能是在区间 [r - i + 1,l + i - 1] 内。
求出每个区间求并即可。
注意:如第 i 个时间点导出的起始点区间长度小于 i ,则无解。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int T, n, s[N], l[N], r[N];
int main() {
scanf("%d", &T);
while(T --) {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) s[i] = 0, l[i] = 0;
for(int i = 1, x; i <= n; i ++) {
scanf("%d", &x);
if(!l[x]) l[x] = i;
r[x] = i;
}
int L = 0, R = 0;
for(int i = 1; i <= n; i ++)
if(l[i]) {
if(!L) L = l[i], R = r[i];
else L = min(l[i], L), R = max(R, r[i]);
l[i] = L, r[i] = R;
}
int cnt = 0;
bool flag = true;
for(int i = 1; i <= n; i ++)
if(l[i]) {
int L = max(1, r[i] - i + 1);
int R = min(n, l[i] + i - 1);
if(R - L + 1 < i) flag = false;
else s[L] ++, s[R + 1] --;
cnt ++;
}
int t = 0, ans = 0;
for(int i = 1; i <= n; i ++) {
t += s[i];
if(t == cnt) ans ++;
}
if(!flag) ans = 0;
printf("%d\n", ans);
}
return 0;
}
E. Tree Pruning
选定一个深度,深度大于的节点需要全部剪掉,深度小于的子节点及枝桠需要剪掉。
因此从 1 开始枚举深度,深度每增加 1 ,所有叶子节点伸长一个单位(或者分叉)。没有伸长的叶子节点回溯修剪掉多余的枝桠。
每次更新答案,取最小值即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int T, n, ans, cnt[N], fa[N];
vector<int> g[N];
void get_ans(int rt) {
queue<int> q;
q.push(rt); cnt[rt] = 1; fa[rt] = 0;
int res = n - 1;
while(q.size()) {
int t = q.size();
for(int i = 0; i < t; i ++) {
int x = q.front(); q.pop();
for(auto y: g[x]) {
if(y == fa[x]) continue;
q.push(y);
cnt[x] ++;
fa[y] = x;
res --;
}
if(!cnt[x]) {
res ++;
while(-- cnt[fa[x]] == 0) res ++, x = fa[x];
}
}
ans = min(ans, res);
}
}
int main() {
scanf("%d", &T);
while(T --) {
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
g[i].clear(), cnt[i] = 0;
for(int i = 2, u, v; i <= n; i ++) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
ans = n;
get_ans(1);
printf("%d\n", ans);
}
return 0;
}
标签:975,const,fa,int,scanf,Codeforces,--,while,Div
From: https://www.cnblogs.com/lingo12321/p/18445027