(题解)Codeforces Round #839 (Div. 3) A B C D E

A. A+B?

原题指路:Problem - A - Codeforces

题意(2s):

有\(t(1\leq t \leq 100)\)组测试数据,每组数据给出形如\(a+b\)(其中\(0 \le a ,  b \le 9\))的式子(包括其中的加号),然后输出表达式的值

思路:

运用scanf格式化读入即可。

代码:

#include<bits/stdc++.h>
using namespace std;

int main() {

    int t; cin >> t;

    while(t > 0) {
        int a, b;
        scanf("%d+%d",&a,&b);
        int c = a + b;
        printf("%d\n",c);
        t--;
    }

    return 0;
}

B. Matrix Rotation

原题指路:Problem - B - Codeforces

题意(2s):

有\(t(1\leq t \leq 1000)\)组测试数据,每组数据给一个2x2的矩阵,矩阵中的元素各不相同,问这个矩阵能否通过若干次的顺时针旋转,使得矩阵每一行每一列的第一个数都小于第二个数。(图片来自题目截图)

思路:

要使每一行每一列的第一个数小于第二个数字,我们先设矩阵从上到下从左到右四个数字分别为\(a, b, c, d\),那么满足如下条件:\(a < b\),\(a < c\),\(b < d\),\(c < d\)。那么也就是说,第一个数字\(a\)是四个数字中最小的,最后一个数字\(d\)是四个数字中最大的,对于第二个和第三个数字不作其他要求。因此只需要第一个数字最小,第四个数字最大则为符合条件的矩阵。而这个矩阵可以进行顺时针的旋转,因此第二个数字最小,第三个数字最大也符合条件(顺时针旋转三次即可得到符合题目条件的矩阵),第四个数字最小,第一个数字最大也符合条件(顺时针旋转两次即可),第三个数字最小,第二个数字最大也符合条件(顺时针旋转一次即可)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define CaseT int CaseT; cin >> CaseT; while(CaseT--)
void solve() {
    int a, b, c, d; cin >> a >> b >> c >> d;
    int xiao = min(a, min(b, min(c, d)));
    int da = max(a, max(b, max(c, d)));
    if (a == xiao && d == da) {
        cout << "YES" << endl;
        return;
    }
    if (a == da && d == xiao) {
        cout << "YES" << endl;
        return;
    }
    if (b == da && c == xiao) {
        cout << "YES" << endl;
        return;
    }
    if (b == xiao && c == da) {
        cout << "YES" <<endl;
        return;
    }
    cout << "NO" << endl;
    return;
}

int main() {
    CaseT
    solve();
    return 0;
}

C. Different Differences

原题指路:Problem - C - Codeforces

题意(2s):

有\(t(1\leq t \leq 819)\)组测试数据,每组数据给出两个数字,\(k\)和\(n\),表示一个序列中有\(k\)个整数,这些整数的范围是\(1 \leq a_i \leq n\),该序列满足后一项严格大于前一项,且后一项减去前一项所得到的差的不同元素尽可能的多,输出这样的一个序列。

例子:如当\(k = 5\),\(n = 9\)时,其中的一个合理的序列是\(1 2 4 7 8\)因为,他的差的分别为\(2 - 1 = 1\),\(4 - 2 = 2\),\(7 - 4 = 3\),\(8 - 7 = 1\),其中不同的元素有\(1,2,3\)三种。

思路:

由于序列严格递增,所以后一个数至少比前一个数字大一。如果我们前面的数字递增太快了,那么后面的序列就会出现放不下的情况。比如要放十个数字,\(n = 20\),可是你却在令第五个数字为\(17\),那么后面的五个数字就无论如何都放不下了。所以我们首先要保证放完当前数字后剩下的数字还有的放,即放完\(i\)个数后应满足\(k - i \leq n - a_i\)的条件。其次,为了得到最多的不同的差的元素,而且又要整个序列递增的快,我们可以让序列从\(1\)开始递增,每次多增加\(1\),也就是\(a_{i + 1} - a_i = i\)。放完数之后判断一下后面的数还能不能放,如果不能的话,那么就从这一项开始每个都是递增\(1\)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define CaseT int CaseT; cin >> CaseT; while(CaseT--)

void solve() {
    int k, n; cin >> k >> n;

    int sum = 1;
    int j = 1;
    int a[50];
    int static i = 1; 
    for (int i = 1; i <= k; i++) {
            a[i] = sum;
            sum += j;
            j++;
            if (sum + (k - i - 1) == n) {
                int j = 0;
                for (i++; i <= k; i++) {
                    a[i] = sum + j; j++;
                }
            }
            if (sum > n - (k - i) && i!= k) {
                sum = sum - j;
                int j = 1;
                for (i; i <= k; i++) {
                    a[i] = sum + j; j++;
                }
            }
            
    }

    for (int i = 1; i <= k; i++) {
        cout << a[i] << " ";
    }
    cout << endl;
}

int main() {
    CaseT
    solve();
    return 0;
}

D. Absolute Sorting

原题指路:Problem - D - Codeforces

题意(2s):

有\(t(1\leq t \leq 2e4)\)组测试数据。每组测试数据一个长度为\(n\)的序列,问是否存在一个整数\(x(0 \leq x \leq 1e9)\)使得,序列中的每一个数替换为\(\left|a_i - x \right|\)后,这个序列能够变成非严格单调递增的序列(即后一项大于等于前一项)。

思路:

我们如果从几何意义上去考虑\(\left|a_i - x \right|\)中的这个绝对值的话,我们可以将这道题转化为,在平面直角坐标系中有\(n\)个点,每个点的坐标是\((i, a_i)\),然后有一条平行于\(x\)轴的直线\(l:y = C(0 \leq C \leq 1e9)\),然后保证从左到右每一个点到这条线的距离非严格递增。

 所以题目就转变成了,给一串点,然后找到这么一条直线,使得,每个点到这条线的距离递增。我们可以考虑维护两个数值,上边界和下边界。

如果接下来的一个点比上一个点大,那么就能确定这条线的下边界(即这条线要在下边界的上边)。假设这两个点分别为\(a\)和\(b\),且\(a \leq b\),那么当直线在\(b\)上方即\(C \geq b\)时显然成立,当直线在\(a\)和\(b\)之间的时候,当\(C \geq \frac{a +b}{2}\)时也能满足点到直线的距离非严格单调递增的条件。

 同理,当接下来的一个点比上一个点小的时候,就能够确定这条线的上边界了。

用上述确定上下边界的方法在遍历数组的时候不断更新这条线的上下边界,直到数组遍历完之后,如果上下边界出现矛盾,即下边界高于上边界,这说明这样例无解。若有解则随意输出一个在上下边界中的数字即可。

代码:

#include<bits/stdc++.h>
using namespace std;
#define CaseT int CaseT; cin >> CaseT; while(CaseT--)

const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
int n;
int a[N];

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    int down = 0; int up = INF;
    for (int i = 2; i <= n; i++) {
        if (a[i] == a[i - 1]) continue;
        if (a[i] > a[i - 1]) { //更新基准线上界
            int temp = (a[i] + a[i - 1]) / 2; //上边界是下取整,直接做除法就好了
            if (temp < up) up = temp; //上边界下移。
        }
        if (a[i] < a[i - 1]) {
            int temp = (a[i] + a[i - 1]);
            if (temp % 2 == 1) temp = temp / 2 + 1; //下边界是上取整
            else temp /= 2;
            if (temp > down) down = temp; //更新下边界
        }
        if (up < down) {
            cout << -1 << endl;
            return;
        }
    }

    cout << down << endl;
}

int main() {
    CaseT
    solve();
    return 0;
}

E. Permutation Game

原题指路:Problem - E - Codeforces

题意(4s):

有\(t(1\leq t \leq 1000)\)组测试数据,每组数据给定\(n\)个互不相同的且小于等于\(n\)的整数,一开始的时候,每个数字初始颜色是红色。有两个玩家交替操作,每轮操作他们都有一下三种选择:①保持红色元素的数字不动,可以将所有蓝色数字进行交换位置。②将一个红色的数字变成蓝色。③跳过自己当前回合。最后,如果序列是一个升序序列,那么第一位玩家胜利;如果是一个降序序列,那么第二位玩家胜利;如果没有人能胜利,那么就是平局。

思路:

一位玩家想要胜利,那么他必须尽可能的在尽可能少的步骤得情况下,使序列变成相应情况的序列。最少步骤的情况应该是将序列中不符合自己情况的数字变成蓝色,然后最后一步一次将所有的蓝色数字交换位置得到获胜序列。

因此我们可以把序列中的数字分为三类,第一类是两个玩家想要获得胜利都需要变成蓝色的数字。第二类是第一位玩家想要获得胜利就必须变成蓝色的数字。第三类是是第二位玩家想要获得胜利就必须变成蓝色的数字。

为什么我们要把序列中的数字分成这三类呢,我们可以这样进行考虑。我们先考虑平局的情况,然后两个玩家胜利的情况各占剩下的另一半。然后如何出现平局的局面呢,那就是全场只剩下一张需要变成蓝色的数字,先手把他颜色变了,后手就能够通过操作一进行排序获得胜利。一号玩家要获得胜利,需要将所有第一二类数字变颜色,二号玩家要获得胜利需要把所有第二三类数字变颜色。如果若干操作后场上只剩下第一类数字,那么就变成了平局,如果场上只剩下了第二类数字,那么为玩家二胜利,反之亦然。因此一号(二号)玩家要优先将第二(三)类数字变颜色,再把第一类数字变颜色。如果一号玩家能够在二号玩家将第三类数字全部变色之前将第一二类数字变色,那么一号玩家胜利。二号玩家因为是后手,所以要先一步在一号玩家将第二类数字变色前将所有一三类数字变色。其余情况平局。

代码:

#include<bits/stdc++.h>
using namespace std;
#define CaseT int CaseT; cin >> CaseT; while(CaseT--)
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int N = 5e5 + 55;
int n;

void solve() {
    cin >> n;
    int one = 0; int two = 0; int both = 0;
    for (int i = 1; i <= n; i++) {
        int x; cin >> x;
        if (x != i && x != n - i + 1) both++;
        else if(x != i) one++;
        else if(x != n - i + 1) two++;
    }

    if (one + both <= two) {
        cout << "First" << endl;
        return;
    }
    if (two + both < one) {
        cout << "Second" << endl;
        return;
    }
    cout << "Tie" << endl;

}

int main() {
    CaseT
    solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值