Codeforces Round #839 (Div. 3)

A. A+B?

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
const ll MOD = 998244353;
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        string s;
        cin >> s;
        cout << s[0] + s[2] - '0' - '0' << endl;
    }
    return 0;
}

B. Matrix Rotation

题意:判断2*2矩阵按行列是否严格递增,可以执行的操作是将矩阵进行90度旋转。

思路:按n维矩阵处理,先旋转,再判断,4次旋转是一个周期,判断4个状态是否有一个状态符合题意。需要写矩阵旋转90度函数,判断矩阵是否递增的函数。 矩阵旋转:先将矩阵转置,再将矩阵列按左右向中间移动的顺序依次互换。 判断矩阵是否严格递增:按行判断依次,按列判断依次即可。复杂度为O(n²)

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
int n = 2;
bool if_beautiful(vvi &a){
    for (int i = 0; i < n; ++i){
        for (int j = 0; j < n - 1; ++j){
            if (a[i][j] > a[i][j + 1]) return false;
        }
    }
    for (int i = 0; i < n; ++i){
        for (int j = 0; j < n - 1; ++j){
            if (a[j][i] > a[j + 1][i]) return false;
        }
    }
    return true;

}
void rotation(vvi &a){
    for (int i = 0; i < n; ++i){
        for (int j = i + 1; j < n; ++j){swap(a[i][j], a[j][ i]);}
    }
    for (int i = 0; i < n; ++i){
        int l = 0, r = n - 1;
        while(l < r) swap(a[i][l++], a[i][r--]);
    }
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        vvi a(n, vi(n));
        for (int i = 0; i < n; ++i){
            for (int j = 0; j < n; ++j) cin >> a[i][j];
        }
        bool ok = if_beautiful(a);
        for (int i = 0; i < 4 && !ok; ++i){rotation(a); ok = if_beautiful(a);}
        cout << (ok ? "YES" : "NO") << endl;
    }
    return 0;
}

因为是二维数组,所以可以针对题目写出简单的2维矩阵转置和判定的方法:

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
const ll MOD = 998244353;
bool if_true(vector<vi>& a){
    for (int i = 0; i < 2; ++i){
        if (a[i][0] > a[i][1]) return false;
        if (a[0][i] > a[1][i]) return false;
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n = 2;
        vector<vi> a(2, vi(2, 0));
        bool ok = false;
        for (int i = 0; i < n; ++i){for (int j = 0; j < n; ++j) cin >> a[i][j];}
        for (int i = 0; i < 4; ++i){
            for (int i = 0; i < n; ++i){
                for (int j = 0; j <= i; ++j){swap(a[i][j], a[j][i]);}
            }
            swap(a[0][0], a[0][1]);
            swap(a[1][0], a[1][1]);
            if (if_true(a)) {ok = true; break;}
        }
        cout << (ok ? "YES\n" : "NO\n");
    }
    return 0;
}

或者还有一种很简单的写法,将矩阵展开成一维的,并判断最大和最小值的下标是否满足差值为2这个条件

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        vi a(4);
        for (int i = 0; i < 4; ++i) cin >> a[i];
        swap(a[2], a[3]);
        int min_index = int(min_element(a.begin(), a.end()) - a.begin());
        int max_index = int(max_element(a.begin(), a.end()) - a.begin());
        bool ok = max_index == (min_index + 2) % 4;
        cout << (ok ? "YES" : "NO") << endl;
    }
    return 0;
}

总结:对矩阵的操作不熟悉,看到题目要求操作是可以对矩阵进行旋转,一时间想不起来矩阵怎么旋转的。所以矩阵的旋转应该是:先转置,再换列。

C. Different Differences

题意:给定一个k,和n,k代表数组长度,n代表可以选取的最大数值。创建一个长度为k的严格递增数组,元素值范围属于[1, n],并让这个数组中的a[i] - a[i - 1]出现的不同的数尽可能的多。且k不大于n.

比如:[1,3,4,7,8] is 3 since the array [2,1,3,1]contains 3 different elements: 2, 1 and 3.

思路:构建这种数组,让相邻两个元素的差值出现尽可能出现之前没出现过的数,容易想到构建差值为1,2,3....m的序列。所以按照给定的k和n,可以按照规则构造出确定的序列。序列中第一个最大数肯定是n,第二个肯定是n - 1,这样差值为1。第二个应该为n - 3, 这样差值为2....

令i∈[0, k), 当前选取的数应该为n - i,并更新 n -= i,并且操作的前提是n - i ≥ k - i => n >= k。因为如果n < k说明现在还需要添加k个数,但是从1到n已经不能组建有k个数的严格递增序列了。比如n = 3, k = 4。当 n = k时,当前选取的数只能是n - 1,事后 n -= 1。

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
const ll MOD = 998244353;

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n, k;
        cin >> k >> n;
        string ans = "\n";
        for (int i = 0; i < k; ++i){
            if (n >= k){ans = to_string(n - i) + " " + ans; n -= i;}//n - i >= k - i
            else {ans = to_string(n - 1) + " " + ans; n -= 1;}
        }
        cout << ans;

    }
    return 0;
}

总结:这个题目的关键点在于理解根据相邻两个元素的差值不同如何构造序列,以及能否继续构造的条件。

D. Absolute Sorting

题意:给定一个乱序数组,判断是否存在一个数值x,让这个数组减去x后非递减排序。并且a[i] = abs(a[i] - x)。如果存在,输出x,否则输出-1。

思路:这个题看上去没什么思路,通过找规律发现让数组减去一个数后严格递增,那么存在一个数x,让x减去这个数后使后面所有的数都满足题意,通过遍历,不断的更新x值,更新完后再遍历一次数组,判断是否符合题意即可。对于两个递减的数a,b,x值应该为小的数加上(abs(a - b) + 1) / 2。如果后面出现了更大的x,那么更新这个x为更大的x。时间复杂度为O(n)

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;
        vi a(n);
        for (int i = 0; i < n; ++i) cin >> a[i];
        bool ok = true;
        int rst = 0;
        for (int i = 1; i < n; ++i){
            int t = a[i] - a[i - 1];
            if (t < 0) {rst = max(rst,(abs(a[i] - a[i - 1]) + 1) / 2 + a[i]);}
            else if (t > 0){
                if (abs(a[i - 1] - rst) > abs(a[i] - rst)){ ok = false; break;}
            }
        }
        for (int i = 1; i < n; ++i){
            if (abs(a[i] - rst) < abs(a[i - 1] - rst)) {ok = false; break;}
        }
        cout << (ok ? rst : -1) << endl;
    }
    return 0;
}

总结:这个题的关键点在于理解当前元素x的选取,对后面元素的影响,以及x的选取规则。所以要找出前缀子序列中最小的x,并且不断更新x,使x能满足所有前缀子序列。这个题目好像也可以在判定的过程中直接得出结果,不需要二次判定,但是如果不加二次判定的话,42 43 42这个数据跑不过去,暂时没想到更好的办法。

E. Permutation Game

题意:给定一个乱序的permutation数组,定义初始时所有的元素值都为红色,有两个pllayer参加这个游戏。每个playper可以进行这样的操作:1、把红色染成蓝色 2、让蓝色的元素重新排列 3、跳过这个turn。 如果player1先把数组弄成升序,那么player1胜。如果是降序,那么player2胜,如果经过10的1000次方回合后没有胜负,那么没人取胜。问:如果每个player都play optimally,哪个运动员会胜出。

思路:判断哪个运动员会胜出,就看元素排列先排成升序还是降序。要排列元素,先要将需要排列的元素染成蓝色,所以这个题的关键在于染色的次数,如果某一个运动员先将需要排列的元素染成了蓝色,那么这个运动员胜出。否则将没有赢家。

所以需要输入数组元素,并且判断当前元素是否已经在升序,或者降序的位置。如果处于升序的位置,那么player1不需要将他染色,如果处于降序的位置,那么player2不需要将他染色,如果既不升序也不降序,那么player1和player2都需要将他染色。统计出两个player需要染色的元素数目,以及共同需要染色的元素数目。如果有一方的染色数目减去共同染色的数目后小于另一方的染色数目,那么这个运动员胜出。

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;
        vi a(n);
        for (auto &x : a){ cin >> x; x -= 1;}
        int first_blue = 0, second_blue = 0, both_blue = 0;
        bool ok;
        for (int i = 0; i < n; ++i){
            bool if_first = i != a[i];
            bool if_second = n - 1 - i != a[i];
            first_blue += if_first;
            second_blue += if_second;
            both_blue += if_first && if_second;
        }
        if (first_blue + both_blue <= second_blue) cout << "First\n";
        else if (second_blue + both_blue < first_blue) cout << "Second\n";
        else cout << "Tie\n";
    }
    return 0;
}

总结:这个题目一开始没有理解重点在哪里,只找出了两个运动员分别需要染色的元素数目,没有理解到共同需要染色的数目是可以让染色数目多的运动员少染一些元素。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值