Codeforces Round #668 (Div. 2)A~D总结

比赛传送门

Codeforces Round #668 Div. 2

A题

☠速度保持(2min出)

题意
长度为n的排列是一个数组,其中包含n个从1到n的任意整数的任意整数。

F(p)= sort([p1 + p2,p2 + p3,…,pn-1 + pn])。

例如,如果n = 4且p = [1,4,2,3],
则指纹由F(p)= sort([1 + 4,4 + 2,2 + 3])= sort([5,6,5])= [5,5,6]。

您将得到长度为n的排列p。
您的任务是找到具有相同指纹的其他排列p’。
如果存在一些索引i使得pi≠p’i,则认为两个置换p和p’是不同的。

题解
倒着输出就好了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e4 + 10;
const int INF = 1e9 + 7;
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        int a[102];
        for(int i = 0; i < n; i++)scanf("%d", &a[i]);
        for(int i = n - 1; i >= 0 ; i--) printf("%d ", a[i]);
        printf("\n");

    }
}

B题

☠思路理清楚再写,别越弄越糊涂了!

题意
一个由n个整数组成的数组a,保证 ∑ i = 0 n − 1 = 0 ; \sum_{i = 0}^{n-1} = 0; i=0n1=0;

在一个操作中,您可以选择两个不同的索引i和j(1≤i,j≤n),将ai减1,然后将aj加1。
如果i <j,则此操作是免费的,否则将花费一枚硬币。

为了使所有元素等于0,您必须花费多少枚硬币?

题解
把每个正整数与后面的负数相加,直到和为负数,或者遍历完成,结束,存入另一个数组里。
保证最后这个数组的形式为 :负数 负数 … 负数 正数 … 正数 正数
把所有的正数相加,即为答案。
(因为,这种情况下,任意两个数,ai < aj, ai再减一 aj 再加一会浪费。
接下去,为由不用硬币 到 用 硬币 的转折状态)

我的代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e5 + 10;
const int INF = 1e9 + 7;
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        ll a[MAX] = {0ll};
        ll b[MAX] = {0ll};
        for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
        int cnt = 0;
        for(int i = 0; i < n;) {
            if(a[i] <= 0) b[cnt++] = a[i++];
            else {//由正数开始
                ll tmp = a[i];
                i++;
                while(1) {
              		//相加为负数,则终止
                    if(tmp < 0) break;
                    tmp += a[i++];
                    if(i >= n) break;
                }
                b[cnt++] = tmp;
            }
        }
        int pos = 0;
        for(int i = 0; i < cnt; i++) {
            if(b[i] < 0) pos = i;
        }
        ll ans = 0;
        for(int i = pos + 1; i < cnt; i++) {
            ans += b[i];
        }
        printf("%lld\n", ans);
    }
}

C题

☠别慌,别乱

题意
给出n个字符 由0 和1 以及?(?可以变成0 或 1)组成的数组

问能不能做到每k个,就有相同数量的1,以及1的数量等于k / 2

题解
以k为循环,k + i,2 * k + i, 3 * k + i . . .中有明确两个不一样,那么一定是NO
如果,只出现一种数字, 这个数字的个数++,要求两个个数不能大于k / 2.

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e5 + 10;
const int INF = 1e9 + 7;
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, k;
        scanf("%d%d", &n, &k);
        string a;
        cin >> a;
        int cnt0 = 0, cnt1 = 0;
        bool flag = 1;
        for(int i = 0; i < k; i++) {
            int tmp = -1; //!
            for(int j = i; j < n; j += k) {
                if(a[j] == '?') continue;
                if(tmp != -1 && tmp != a[j] - '0') {//虽是?,但是明确有两个不一样
                    flag = 0;
                    break;
                }
                tmp = a[j] - '0';
            }
            if(tmp != -1) {
                if(tmp == 0) cnt0++;
                else cnt1++;
            }
        }
        if(flag && cnt1 <= k / 2 && cnt0 <= k / 2) printf("YES\n");
        else printf("NO\n");
    }
}

D题

☠树上博弈,其实我是被内心恐惧 树 的!

题意

在一棵树上,Alice 和 Bob在两个点上,可以移动的距离为da 和 db
如果 Alice 可以与 Bob 到一个点上,则Alice 赢,反之Bob赢。

题解

情 况 一 情况一

如果Alice和Bob之间的距离小于等于da,那么Alice就赢了。

思考:
临界条件为:
Alice 和 Bob 可以在树最长的链上–树的直径上运动

情 况 二 情况二

当Alice和Bob之间的距离为da+1,也就是若Alice再靠近Bob一步且Bob不操作,Bob就输了。这个时候,Bob就需要跳到离Alice新位置的距离大于da的位置。Alice用最优操作的情况下,Bob的移动距离要大于2 * da +1。
(db >= 2 * da + 1)
且要使操作允许,树的直径 要 >= 2 * da +1

结 论 : 结论:
当且仅当Alice和Bob的初始距离大于da,且db和树的直径都大于等于2 * da +1时,Bob胜,反之Alice胜。

#include <bits/stdc++.h>
using namespace std;
const int MAX = 2e5 + 10;
int n, a, b, da, db;
int diam;
int dist;
int deep[MAX];
vector <int> G[MAX];
int root1, root2;
void dfs(int u, int fa, int &diam, int &root) {//diam,root要变的
    deep[u] = deep[fa] + 1;
    if(diam < deep[u]) {
        diam = deep[u];
        root = u;
    }
    
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(v == fa) continue;
        dfs(v, u, diam, root);
    }
}

int main(){
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d%d%d%d", &n, &a, &b, &da, &db);
        for(int i = 1; i <= n; i++) G[i].clear();
        for(int i = 1; i < n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        diam = 0;//直径
        root1 = 0, root2 = 0;
        dfs(b, 0, diam, root1);
        dist = deep[a] - deep[b];//在第一个dfs之后
        dfs(root1, 0, diam, root2);
        diam--;
        
        if(dist > da && db >= 2 * da + 1 && diam >= 2 * da + 1)
            printf("Bob\n");
        else printf("Alice\n");
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值