[Codeforces Round #669 (Div. 2)]1407




竞赛首页 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 1n 的序列,要求可以确定这个序列
允许最多 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 的条件为:

  1. i + 1 = j i+1=j i+1=j
  2. 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,...,hj1)<min(hi,hj)
  3. 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,...,hj1)

问要跳到第 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值