Codeforces Round #468【solved :5 / 6】

931A

题意:很简单的题,在数轴上给定两个点,两个人相向而行,每个人走第x格的体力花费是x。问你两个人怎么走,直到见面时体力花费加和最小。

思路:大力感知一下就好了。

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

int main()
{
    int a, b;
    scanf("%d%d", &a, &b);
    int delta = max(a, b) - min(a, b);
    int n = delta / 2;
    int ans = (1 + n) * n + (delta & 1 ? n + 1 : 0);
    printf("%d\n", ans);
    return 0;
}

931B

题意:1-n,进行锦标赛,相邻的俩俩胜者不断决斗直到最后,问a和b两个队伍能否在总决赛相会。

思路:如果把整个过程看成一颗二叉树。显然就是一个不断找父节点的问题,对于二叉树我们很熟悉,子节点编号/2就是父节点的编号,不断向上即可,看看他们的共同父节点(或者说是LCA)是否为根即可。

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

int main()
{
    int n, a, b;
    scanf("%d%d%d", &n, &a, &b);
    int ans = 0;
    while(a != b)
    {
        a = (a + 1) / 2, b = (b + 1) / 2;
        ans++;
    }
    if((1 << ans) == n) puts("Final!");
    else printf("%d\n", ans);
    return 0;
}

931C

题意:给出一个序列,其中所有元素的最大值和最小值的差保证不超过2,问找到一个序列(最大值不超过原序列的最大值,最小值不小于原序列的最小值)使得这两个序列的平均值相同且相同的元素最少,问最少的相同元素有几个,并打印出该序列。

思路:显然改变这个序列,无非是把2和0两个元素改变成1和1,或者把两个1改变成2和0。按照最大最小值的差值分类讨论,如果差值为0或者1,显然最少的相同元素是n个,也就是说只能找到原序列满足条件。如果差值为2,那么就按照之前说的改变方法,取一个最少相同的即可。

#include <bits/stdc++.h>
using namespace std;
int a[100000 + 5];

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)  scanf("%d", &a[i]);
    sort(a, a + n);
    int delta = *max_element(a, a + n) - *min_element(a, a + n);
    if(delta == 2)
    {
        int base = *min_element(a, a + n);
        int one = 0, two = 0, zero = 0;
        for(int i = 0; i < n; i++)
        {
            if(a[i] == base) zero++;
            else if(a[i] == base + 1)   one++;
            else two++;
        }
        int t1 = 2 * min(zero, two), t2 = one / 2 * 2;
        if(t1 >= t2)
        {
            printf("%d\n", n - t1);
            vector<int>ans;
            for(int i = 0; i < t1 / 2; i++) ans.push_back(base + 1), ans.push_back(base + 1);
            for(int i = 0; i < zero - t1 / 2; i++)  ans.push_back(base + 0);
            for(int i = 0; i < two - t1 / 2; i++)   ans.push_back(base + 2);
            for(int i = 0; i < one; i++)    ans.push_back(base + 1);
            for(int i = 0; i < n; i++)  printf("%d%c", ans[i], i + 1 == n ? '\n' : ' ');
        }
        else
        {
            printf("%d\n", n - one / 2 * 2);
            vector<int>ans;
            for(int i = 0; i < t2 / 2; i++) ans.push_back(base + 0), ans.push_back(base + 2);
            for(int i = 0; i < zero; i++)  ans.push_back(base + 0);
            for(int i = 0; i < two; i++)   ans.push_back(base + 2);
            for(int i = 0; i < one - t2; i++)    ans.push_back(base + 1);
//            cout<< t2 <<" " << zero <C< " " <<two <<" " << one - t2 << endl;
            for(int i = 0; i < n; i++)  printf("%d%c", ans[i], i + 1 == n ? '\n' : ' ');
        }
    }
    else
    {
        printf("%d\n", n);
        for(int i = 0; i < n; i++)  printf("%d%c", a[i], i + 1 == n ? '\n' : ' ');
    }
    return 0;
}

931D

题意:给出一棵树,然后告诉你每个节点初始有一个苹果,每一个单位时间,你会从根节点取走所有的苹果,每一个单位时间,苹果向其父节点挪动一次。保证父节点的苹果先于儿子节点的苹果挪动,所以不会有冲突。但是同一个单位时间,一个节点,每两个苹果就会发生神奇的现象,两个苹果都消失,也就是说只能保留n&1个苹果。问你一共能取走几个苹果。

思路:很容易发现就是一个&1的方式,每一步&1的过程,我们是不是可以暂时保留,最后才&1的结果是不是一样的。所以这道题就变成了,dfs以后,每一层的节点数量&1加和即可。

#include <bits/stdc++.h>
using namespace std;
vector<int>G[100000 + 5];
vector<int>level;
void dfs(int u, int fa, int deep)
{
    level[deep]++;
    for(auto o : G[u]) dfs(o, u, deep + 1);
}
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 2, x; i <= n; i++)  scanf("%d", &x), G[x].push_back(i);
    level.resize(n);
    dfs(1, -1, 0);
    int ans = 0;
    for(auto o : level) ans += (o & 1);
    printf("%d\n", ans);
    return 0;
}

931E

题意:给你一个小写字母字符串,A会把这个序列截断把后半部分补到前半部分之前,形成新的序列,然后告诉你这个新的序列的第一个字母是什么,并且允许你询问一次,这个新序列中任意一个位置的字母是什么,并告诉你答案,问你能否唯一的知道原序列被截断的位置,如果可以,则算你赢,问你赢的最大概率是多少。

思路:我们可以预处理出dp[i][j][k]:字母i和字母j距离为k一共在原序列中出现了几次。统计答案的时候,只需要对于每一个字母i,枚举距离为k的时候,看有几个字母j满足dp[i][j][k]=1,(这个过程等价于,告知你的第一个位置的字母是i,假设你唯一的知道这个原序列被截断的位置为k,那么A告诉你的字母为j的时候是否满足题意),显然对于每一个字母i,找到一个满足dp[i][j][k]的字母j最多的 k m a x ,将其累加起来即可。(这个过程等价于,告知你的第一个位置的字母是i,你将选择询问距离为 k m a x 的那个字母j,这个举动将使你有最大的胜率)

#include <bits/stdc++.h>
using namespace std;
int cnt[26][26][5000 + 5];
int vis[26];
int main()
{
    string str;
    cin >> str;
    for(int i = 0; i < str.size(); i++)
    {
        vis[str[i] - 'a'] = 1;
        for(int dist = 1; dist < str.size(); dist++)
        {
            cnt[str[i] - 'a'][str[(i + dist) % str.size()] - 'a'][dist]++;
        }
    }
//    puts("?");
    double ans = 0;
    for(int i = 0; i < 26; i++)
    {
        int mx = 0;
        for(int dist = 1; dist < str.size(); dist++)
        {
            int temp = 0;
            for(int j = 0; j < 26; j++)
            {
                if(cnt[i][j][dist] == 1)    temp++;
            }
            mx = max(mx, temp);
        }
        ans += 1.0 * mx / str.size();
    }
    printf("%.8f\n", ans);

    return 0;

猜你喜欢

转载自blog.csdn.net/qq_29556211/article/details/79524550