[Codeforces Global Round 9]1375




A - Sign Flipping [思维]

目录
题目传送门

题意

可以改变任意位置的数,使 a [ i ] = − a [ i ] a[i] = -a[i] a[i]=a[i]
最终要令长度为 n n n 的数组 a [ ] a[] a[] 中,(保证 n n n 为奇数)
a [ i + 1 ] − a [ i ] > = 0 a[i+1]-a[i] >= 0 a[i+1]a[i]>=0 i i i 的个数至少有 n − 1 2 \frac{n-1}{2} 2n1
a [ i + 1 ] − a [ i ] < = 0 a[i+1]-a[i] <= 0 a[i+1]a[i]<=0 i i i 的个数至少有 n − 1 2 \frac{n-1}{2} 2n1

分析

只要按序输出整数负数交替就可以

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100 + 5;

int a[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            if((i % 2 && a[i] < 0) || (i % 2 == 0 && a[i] > 0))
                a[i] = -a[i];
        }
        for(int i = 1; i <= n; ++i)
            printf("%d%c", a[i], i == n ? '\n' : ' ');
    }
    return 0;
}


B - Neighbor Grid [构造]

目录
题目传送门

题意

一个 n × m n \times m n×m 的矩阵,若矩阵上为 k > 0 k > 0 k>0,则表示与它相邻的格子为非零数的个数有 k k k 个。
每个格子上的数可以 + 1 +1 +1 地增加。
构造一个满足给定要求的矩阵,如果不存在输出 − 1 -1 1

分析

只要满足 k < = 4 − 边 界 的 个 数 k <= 4 - 边界的个数 k<=4 就是有解的情况

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 300 + 5;

int a[maxn][maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= m; ++j)
                scanf("%d", &a[i][j]);
        bool f = true;
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                int x = 4 - (i == 1 || i == n) - (j == 1 || j == m);
                if(a[i][j] > x) {
                    f = false; break;
                }
                a[i][j] = x;
            }
            if(!f)  break;
        }
        if(!f)  puts("NO");
        else{
            puts("YES");
            for(int i = 1; i <= n; ++i)
                for(int j = 1; j <= m; ++j)
                    printf("%d%c", a[i][j], j == m ? '\n' : ' ');
        }
    }
    return 0;
}


C - Element Extermination [思维] ★

目录
题目传送门

题意

一段连续增长的子区间中可以缩短成其中一个元素的值
给一个 n n n 个数的数组 a [ i ] , a [ i ] ∈ [ 1 , n ] a[i], a[i] \in [1, n] a[i],a[i][1,n],每个元素都不相同
问最后是否能缩减成数组只包含一个元素

分析

万万没想到,我写了半天的代码,竟然只要判断首尾 o(╥﹏╥)o
其实只需要满足 a [ 1 ] < a [ n ] a[1] < a[n] a[1]<a[n] 则一定可以缩减为只剩 1 个元素,可以通过找规律
比如说一个数组 [2 1 5 3 4]
由于 a [ 1 ] < a [ n ] a[1] < a[n] a[1]<a[n] 满足
a [ n ] < n a[n] < n a[n]<n,则 a [ i ] = n a[i] = n a[i]=n 必然存在于 1 < i < n 1 < i < n 1<i<n 中,则前部分 a [ 1 ] . . . a [ i ] a[1] ... a[i] a[1]...a[i]最后必然能缩减为 a [ 1 ] a[1] a[1]
类似这样推导

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;

int a[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        printf("%s\n", a[1] > a[n] ? "NO" : "YES");
    }
    return 0;
}


D - Replace by MEX [暴力]

目录
题目传送门

题意

n n n 个数的数组 a [ i ] a[i] a[i],该数组的 M E X MEX MEX 定义为当前数组中未出现的最小元素(从 0 0 0 开始)
每次可以选择数组中的一个数,用当前数组的 M E X MEX MEX 替换掉
问最后要得到一个非单调递减序列,替换的位置顺序应是如何,输出任意解

分析

可以发现不管怎样替换,都可以最终替换成 [0, 1, 2, …, n-1] 这样的数组
也就是说最后的目标是构造成 a [ i ] = i − 1 a[i] = i - 1 a[i]=i1 这样的数组
n < = 1000 n <= 1000 n<=1000 n 2 n^2 n2 暴力
每次找出当前数组的 M E X MEX MEX,如果 M E X > n − 1 MEX > n - 1 MEX>n1 M E X = n MEX = n MEX=n,则随便找一个 a [ i ] ! = i − 1 a[i] != i - 1 a[i]!=i1 的位置进行替换
否则只要替换成 a [ M E X ] = M E X a[MEX] = MEX a[MEX]=MEX

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 5;

int a[maxn];
int res[maxn];
int cnt[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        memset(cnt, 0, sizeof(cnt));
        for(int i = 0; i < n; ++i) {
            scanf("%d", &a[i]); cnt[a[i]] += 1;
        }
        int k = 0;
        while(true) {
            int pos = 0;
            // for(int i = 0; i < n; ++i)
            //     printf("%d%c", a[i], i + 1 == n ? '\n' : ' ');
            while(pos < n - 1 && a[pos] <= a[pos + 1])  pos += 1;
            if(pos + 1 == n)    break;
            
            pos = 0;
            while(cnt[pos]) pos += 1; // mex
            if(pos >= n) {
                for(int i = 0; i < n; ++i) {
                    if(a[i] != i) {
                        cnt[a[i]] -= 1, cnt[pos] += 1;
                        a[i] = pos, res[k++] = i;
                        break;
                    }
                }
            }else{
                cnt[a[pos]] -= 1, cnt[pos] += 1;
                a[pos] = pos, res[k++] = pos;
            }
        }
        printf("%d\n", k);
        if(k == 0)  puts("");
        for(int i = 0; i < k; ++i)
            printf("%d%c", res[i] + 1, i + 1 == k ? '\n' : ' ');
    }
    return 0;
}


E - Inversion SwapSort [逆序对][构造] ★★★

目录
题目传送门
参考博客 Codeforces 1375 E. Inversion SwapSort —— 想法,贪心

题意

给定一个数组 a [ ] a[] a[],有 n n n 个数
若满足 u < v & & a [ u ] > a [ v ] u < v \& \& a[u] > a[v] u<v&&a[u]>a[v],则两个数可以交换位置(即为逆序对的时候)
问要交换哪几对 ( u , v ) (u, v) (u,v) 后,可以得到不递减序列(这一场好经常出现这个)

分析

需要先对数组排序,按照 a [ i ] a[i] a[i] 升序,然后 i i i 升序这样排序
每次取逆序对的时候就从 a [ i ] a[i] a[i] 小的开始取
找逆序对的时候就找 a [ j ] < a [ i ] & & j > i a[j] < a[i] \&\& j > i a[j]<a[i]&&j>i 的,然后放到数组中

对于一开始找 a [ i ] a[i] a[i] 比较小的处理后,可以将后面的数序列中除了比 a [ i ] a[i] a[i]大的,是不递减的序列
因此处理 a [ i + 1 ] > a [ i ] a[i + 1] > a[i] a[i+1]>a[i] 的时候,也可以保证从后往前依次一个一个交换的时候,可以满足 a [ i ] > a [ j ] a[i] > a[j] a[i]>a[j] 的条件
最终可以再保持后面的数序列中除了比 a [ i + 1 ] a[i + 1] a[i+1]大的,是不递减的序列

举个栗子
[4 2 3 1]
数组 ( a [ i ] , i ) (a[i], i) (a[i],i) 排序后得到
( 1 , 4 ) ; ( 2 , 2 ) ; ( 3 , 3 ) , ( 4 , 1 ) (1, 4); (2, 2); (3, 3), (4, 1) (1,4);(2,2);(3,3),(4,1)
i = 1 (1, 4): 无; → \rightarrow [4 2 3 1]
i = 2 (2, 2): j = 4 j = 4 j=4; → \rightarrow [4 1 3 2]
i = 3 (3, 3); j = 4 j = 4 j=4; → \rightarrow [4 1 2 3]
i = 4 (4, 1); j = 4 , 3 , 2 j = 4, 3, 2 j=4,3,2;
→ \rightarrow [3 1 2 4] → \rightarrow [2 1 3 4] → \rightarrow [1 2 3 4]

Code

#include <bits/stdc++.h>
#define pii pair<int, int>
#define fi  first
#define se  second
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 5;

int a[maxn];
vector<pii> v, v2;

int main() {
    int n;
    scanf("%d", &n);
    v.clear(), v2.clear();
    for(int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
        v.push_back(make_pair(a[i], i));
    }

    sort(v.begin(), v.end());
    for(int i = 0; i < n; ++i) {
        int x = v[i].se;
        for(int j = n - 1; j > x; --j) {
            if(a[x] > a[j])
                v2.push_back(make_pair(x, j));
        }
    }
    printf("%d\n", (int)v2.size());
    for(auto i : v2)
        printf("%d %d\n", i.fi + 1, i.se + 1);

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值