文章目录
竞赛首页 Codeforces Round #669 (Div. 2)
A - Ahahahahahahahaha
题意
给一个长度为 n n n 的数组,仅包含 0, 1
现在最多可以删除 n / 2 n/2 n/2 个字符,要求最后的串满足奇数位置上的数之和等于偶数位置上的数之和
保证 n n n 为偶数
分析
只要保留 0 或者 1 个数比较多的那个
如果是奇数数量就扣掉一个
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 3e5 + 5;
const ll mod = 1e9 + 7;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, x, cnt = 0;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &x);
if(x) cnt+=1;
}
if(cnt * 2 > n) x = 1;
else x = 0, cnt = n-cnt;
if(cnt % 2 && x) cnt -= 1;
printf("%d\n", cnt);
for(int i = 1; i <= cnt; ++i)
printf("%d%c", x, i == cnt ? '\n' : ' ');
// puts("");
}
return 0;
}
B - Big Vova
题意
给出长度为 n n n 的数组,对数组进行重新排列
令数组 c [ i ] = g c d ( a [ 1 ] , a [ 2 ] , . . . , a [ i ] ) c[i] = gcd(a[1], a[2], ..., a[i]) c[i]=gcd(a[1],a[2],...,a[i]),要使数组 c c c 的字典序尽可能大
如果有多种可行排列,任意输出一种
保证给出的数组 a a a 的第一个元素不是整个数组中最大的数
分析
n n n 较小,直接暴力遍历
首先排在第一个位置的肯定是数最大的
之后只要遍历所有还未取的数,找到 gcd 最大的一个数继续
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3 + 5;
const ll mod = 1e9 + 7;
int a[maxn];
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, g = 1;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", a+i);
g = max(g, a[i]);
}
for(int i = 1; i <= n; ++i) {
int ans = 0, pos = 0;
for(int j = 1; j <= n; ++j) {
if(a[j] && __gcd(g, a[j]) > ans)
ans = __gcd(g, a[j]), pos = j;
}
printf("%d ", a[pos]);
g = __gcd(g, a[pos]), a[pos] = 0;
}
puts("");
}
return 0;
}
C - Chocolate Bunny [思维] ★★
题意
给出以个整数 n n n,表示这是一个 1 − n 1-n 1−n 的序列,要求可以确定这个序列
允许最多 2 n 2n 2n 个询问,每个询问自己要给出的格式为 ? x y
然后会得到一个整数 k k k,即 k = a [ x ] % a [ y ] k = a[x] \% a[y] k=a[x]%a[y]
如果可以确定序列了,就输出 !
然后输出这个序列
分析
挺有意思的互动题目
限制的 2 n 2n 2n 容易联想到一个数需要做两次询问
可以发现对于 a [ x ] % a [ y ] a[x] \% a[y] a[x]%a[y] 和 a [ y ] % a [ x ] a[y] \% a[x] a[y]%a[x],可以得到比较小的那个数应该为多少
注意这个输入后要按照的cf题目给的格式
不然会有怪怪的错误
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1e4 + 5;
const ll mod = 1e9 + 7;
int a[maxn];
int main() {
int n;
scanf("%d", &n);
if(n == 1) {
puts("! 1");
}else{
int pos = 1;
for(int i = 2, x, y; i <= n; ++i) {
printf("? %d %d\n", pos, i);
fflush(stdout);
scanf("%d", &x);
printf("? %d %d\n", i, pos);
fflush(stdout);
scanf("%d", &y);
if(x > y) {
a[pos] = x;
pos = i;
}else{
a[i] = y;
}
}
a[pos] = n;
printf("!");
for(int i = 1; i <= n; ++i) printf(" %d", a[i]);
puts("");
}
fflush(stdout);
return 0;
}
D - Discrete Centrifugal Jumps [单调队列优化dp] ★★★
题意
给出一个长度为 n n n 的数组 h h h
一开始在第一个位置,可以从 i i i 跳到 j j j 的条件为:
- i + 1 = j i+1=j i+1=j
- m a x ( h i + 1 , h i + 2 , . . . , h j − 1 ) < m i n ( h i , h j ) max(h_{i+1},h_{i+2},...,h_{j-1}) < min(h_i,h_j) max(hi+1,hi+2,...,hj−1)<min(hi,hj)
- m a x ( h i , h j ) < m i n ( h i + 1 , h i + 2 , . . . , h j − 1 ) max(h_i,h_j) < min(h_{i+1},h_{i+2},...,h_{j-1}) max(hi,hj)<min(hi+1,hi+2,...,hj−1)
问要跳到第 n n n 个位置,至少需要跳几次
分析
参考博客
一般如果 2,3个条件是简单的条件,就可以用dp来解决
不过这边的2,3分别是限制区间最大最小值,这个就可以考虑单调栈
分别维护一个非递增栈和一个非递减栈
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 3e5 + 5;
const ll mod = 1e9 + 7;
int h[maxn];
int down[maxn]; // 非递增
int up[maxn]; // 非递减
int dp[maxn]; // 1 -> i 的最小步数
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &h[i]);
memset(dp, inf, sizeof(dp));
dp[1] = 0;
int topd = 0, topu = 0;
down[++topd] = 1, up[++topu] = 1;
for(int i = 2; i <= n; ++i) {
dp[i] = dp[i-1] + 1;
while(topd > 0 && h[i] > h[down[topd]])
dp[i] = min(dp[i], dp[down[topd--]]+1);
while(topu > 0 && h[i] < h[up[topu]])
dp[i] = min(dp[i], dp[up[topu--]]+1);
dp[i] = min(dp[i], min(dp[down[topd]], dp[up[topu]])+1);
while(h[i] == h[down[topd]]) topd--;
while(h[i] == h[up[topu]]) topu--;
down[++topd] = i, up[++topu] = i;
}
printf("%d\n", dp[n]);
return 0;
}