Codeforces Round #153 (Div. 2)

这次真心是个坑……

一开始把A题题意看错了,上来就敲WA了一次,开始心急,之后B题卡了40多分钟,实在无奈跑去看C,发现水题一道,迅速A了之后瞎搞了一下B题,D题看不懂题意,于是Lock了所有代码跑去hack其他人。

最后只提交了3道。

System Test之后只有A和C通过了,不过靠着各种hack补了600分勉强把B的损失补上,最终排81,顺利紫名。

A题 Little Xor

题目大意:给一个序列,长度不超过100,求任意连续区间异或结果的最大值。

题解:因为最多也就100个数,所以直接N^2暴力即可。

View Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
using namespace std;
#define INF 0x73737373
#define EPS 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
int a[105];
int main()
{
    int n, ret = 0;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    for(int i = 0; i < n; i++)
    {
        int temp = 0;
        for(int j = i; j < n; j++)
        {
            temp ^= a[j];
            ret = max(temp, ret);
        }
    }
    printf("%d\n", ret);
    return 0;
}

B题 Unsorting Array

大坑……最后只有200多个人AC……

题目大意:给一个任意序列,交换其中两个不相同的数字的位置,使其是一个无序的序列。一个序列为升序或降序则认为其有序。

如果序列初始为无序,依然需要交换两个不同的数字,如果不可能使其变为无序,输出-1,否则输出交换的两个数的序号。

题解:纯YY,做法仅供参考……

首先判断输出-1的情况:

1.如果序列长度小于等于2,必然为-1

2.如果序列中所有数字相同,必然为-1

3.如果序列长度等于3,并且开头和结尾的数相同,必然为-1

上述3个情况中漏掉情况3的很多,我的ROOM里只有2个人对了……

如果不为-1则必然可以找到两个可以交换的数。

我们取序列正中间的那个数,然后向左找离它最近的,比它大的数a,比它小的数b。

同时,向右找离它最近的,比它大的数c,比它小的数d。

如果左右都能找到比它大的数,那么原序列无序,交换这两个数依然无序。

如果左右都能找到比它小的数,那么原序列无序,交换这两个数依然无序。

其他情况原序列可能有序,那么我只要随便交换一下找到的a、b、c、d中的某一个即可破坏有序。

View Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
using namespace std;
#define INF 0x73737373
#define EPS 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
vector<int> ori;
int main()
{
    int n;
    scanf("%d", &n);
    bool can = false;
    for(int i = 0; i < n; i++)
    {
        int a;
        scanf("%d", &a);
        ori.push_back(a);
        if(i > 0 && ori[i] != ori[i-1]) can = true;
    }
    if(n == 2)can = false;
    if(n == 3 && ori[0] == ori[2])can = false;
    if(!can) puts("-1");
    else
    {
        int a = INF, b = INF, c = INF, d = INF;
        for(int i = n / 2; i >= 0; i--)
            if(ori[i] > ori[n/2] && a == INF) a = i;
            else if(ori[i] < ori[n/2] && b == INF) b = i;
        for(int i = n / 2; i < n; i++)
            if(ori[i] > ori[n/2] && c == INF) c = i;
            else if(ori[i] < ori[n/2] && d == INF) d = i;

        int r1, r2;
        if(a != INF && c != INF && ori[a] != ori[c]) r1 = a, r2 = c;
        else if(b != INF && d != INF && ori[b] != ori[d]) r1 = b, r2 = d;
        else r1 = min(min(min(a, b), c), d), r2 = n / 2;
        printf("%d %d\n", r1 + 1, r2 + 1);
    }
    return 0;
}

C题 Point on Line

题目大意:X轴上有n个点,给定一个d,要求取三个点其中任意两点间的距离<=d,问共有多少种取法。

题解:很水……

要求任意两点间的距离小于等于d,其实就是要求最左的点和最右的点的距离不超过d。

那么对于任意一个点Ai,如果我们把它作为最左的点,

则我们一定可以找到跟它距离不超过d的最右的点Ar(r >= i),

这样我们可以在r - i个点内随意选两个,共有Cn2种取法。

于是枚举每一个点作为最左的点,把取法求和即可。

View Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
using namespace std;
#define INF 0x73737373
#define EPS 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
int a[105000];
int main()
{
    int n, d;
    scanf("%d%d", &n, &d);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    __int64 ret = 0, k;
    for(int i = 1; i <= n - 2; i++)
    {
        int index = lower_bound(a, a + n, a[i] + d) - a;
        if(a[index] - a[i] <= d)
            k = index - i;
        else if(a[index - 1] - a[i] <= d)
            k = index - i - 1;
        ret += (k * (k - 1)) / 2;
    }
    printf("%I64d\n", ret);
    return 0;
}

D题 Playing with Permutations

 英语拙计……

题目大意:开始你有三个序列

一个长度为n的序列p,其初始值是1、2、3、4、5……n-1、n。

一个长度为n的序列q,其初始值由输入获得。

一个长度为n的序列s,其初始值由输入获得。

接下来你必须执行k步操作,每步操作有两种选择。

1.生成一个新的p,其中newp[i] = p[q[i]]

2.生成一个新的p,其中newp[q[i]] = p[i]

要求你在执行的k-1步操作过程中的任意一步,序列p都不得等于序列s。在执行完第k步操作后,序列p等于序列s。

问这种情况是否可能。

题解:

如果把原文的操作一、二完全看懂的话,很容易就可以看出两个操作是互逆,也就是说如果你对p执行了操作1再执行操作2的话,相当于什么也没做。

知道了这一点就很好处理了。

如果我们执行m1次 操作1 可以使得序列p等于序列s,那么我们先执行(k - m1) / 2次的(操作1、操作2)组合,再执行m1次 操作1 即可。

如果我们执行m2次 操作2 可以使得序列p等于序列s,那么我们先执行(k - m2) / 2次的(操作1、操作2)组合,再执行m2次 操作2 即可。

所以只要求出其中的m1、m2再判断一下k - m1,k - m2是否是偶数就行了。

View Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
using namespace std;
#define INF 0x73737373
#define EPS 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
int p[105], np[105], q[105], r[105];
bool is_same(int n)
{
    for(int i = 1; i <= n; i++)
        if(p[i] != r[i]) return false;
    return true;
}
void init(int n)
{
    for(int i = 1; i <= n; i++) p[i] = i;
}
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++) scanf("%d", &q[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &r[i]);
    init(n);
    if(is_same(n))puts("NO");
    else
    {
        int head = -1, tail = -1;
        for(int i = 1; i <= k; i++)
        {
            for(int j = 1; j <= n; j++)
                np[j] = p[q[j]];
            memcpy(p, np, sizeof(p));
            if(is_same(n))
            {
                head = i;
                break;
            }
        }
        init(n);
        for(int i = 1; i <= k; i++)
        {
            for(int j = 1; j <= n; j++)
                np[q[j]] = p[j];
            memcpy(p, np, sizeof(p));
            if(is_same(n))
            {
                tail = i;
                break;
            }
        }
        if(head == -1 && tail == -1) puts("NO");
        else if(head == 1 && tail == 1 && k != 1) puts("NO");
        else if(head != -1 && (k - head) % 2 == 0) puts("YES");
        else if(tail != -1 && (k - tail) % 2 == 0) puts("YES");
        else puts("NO");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/deadblue/p/2807095.html