首页 > 其他分享 >Codeforces Round 958 (Div. 2)

Codeforces Round 958 (Div. 2)

时间:2024-07-17 12:51:46浏览次数:20  
标签:958 int void Codeforces cin ++ vector Div fag

题目链接:Codeforces Round 958 (Div. 2)

总结:C因为常数没转\(long long\) \(wa\)两发,难绷。

A. Split the Multiset

fag:模拟

Description:给定一个\(n\)和一个\(k\),每次可以将\(n\)减掉一个数\(u\),然后插入\(x\)个数,\(x <= k\),并且插入的数之和等于\(u\)。求将其转化为全\(1\)的最小操作次数。

Solution:因为最后要得到全\(1\),所以每次操作我们插入尽可能多的\(1\),即插入\(1, 1, ..., u - (k - 1)\)。相当于每次将\(n\)减少\(k - 1\)。那么答案为\(k --, (n - 1 + k - 1) / k\),这里是向上取整。

void solve(){
    cin >> n >> k;
    k --;
    if (n == 1){
        cout << 0 << endl;
        return;
    }
    n --;
    cout << (n + k - 1) / k << endl;
}

B. Make Majority

fag: 思维

Description: 给定一个只含\(0\)或\(1\)的字符串,每次操作可以选择一个区间\(l, r\),将这个区间变为一个数(区间内出现次数最多的数)。

问能否将其变为\(1\)。

Solution:手摸几组样例发现:我们可以把所有连续的多个\(0\)变为一个\(0\),如果我们需要将一个\(0\)去掉,那么至少需要两个\(1\)。

  • 那么统计连续\(0\)的区间个数\(x\),\(1\)的个数\(y\)。
  • 当\(y >= x + 1\)时,有解,否则无解。
void solve(){
    cin >> n;
    cin >> s;
    int x = 0, y = 0;
    for (int i = 0; i < n; i ++){
        if (s[i] == '0')
            x ++;
        else
            y ++;
    }
    int xx = 0;
    bool flag = true;
    for (int i = 0; i < n; i ++){
        if (s[i] == '0' && flag){
            xx ++;
            flag = false;
            continue;
        }
        if (s[i] == '1')
            flag = true;

    }
    if (y >= xx + 1){
        cout << "Yes\n";
    }
    else{
        cout << "No\n";
    }
}

C. Increasing Sequence with Fixed OR

fag:位运算

Description:给定一个\(n\),求一个最长的序列,序列满足\(ai < a_{i +1}\),且\(a_i | a_{i + 1} == 1\)。输出序列的长度和序列值。

Solution:显然我们需要将\(n\)转化为二进制。模拟样例后发现,如果\(n\)的二进制含有\(x\)个\(1\),那么序列长度为\(x + 1\)。

然后考虑如何构造。我们只需要依次去掉低位\(1\),就可以满足以上要求。注意对常数进行位运算时,需要将其强制转化为long long

void solve(){
    cin >> n;
    vector<int> ans;
    ans.eb(n);
    for (int i = 0; i < 64; i ++){
        if (n >> i & 1){  // 这一位是1
            ans.eb(n ^ (1LL << i));  // 注意这里
        }
    }
    if (ans[ans.size() - 1]  == 0)  // 注意特判
        ans.pop_back();
    cout << ans.size() << endl;
    sort(ans.begin(), ans.end());
    for (int i = 0; i < ans.size(); i ++){
        cout << ans[i] << " ";
    }
    cout << endl;
}

D. The Omnipotent Monster Killer

fag:树形DP

Description:一颗有\(n\)个点的数,每个点有一个权值\(a_i\),每回合所有点会对玩家造成大小为自身权值的伤害。玩家每回合可以消灭一些点(不能删除被一条边相连的两点)。求玩家受到的最小伤害。

1 <= n <= 3e5
1 <= ai <= 1e12

Solution:只需要最多\(L\)个回合即可,\(L <= log_{2}n + 1\),我们令\(L = 20\)即可,不太会证。

  • 如果一个节点在第\(i\)个回合删除,那么它的伤害为\(i * a_{i}\)

  • 令\(f[x][j]\)表示,\(x\)节点在第\(j\)个回合删除,以\(x\)为根的子树的伤害最小值。\(f[x][j] = j * a_x + \sum_{i \in son(x)}min(f[i][k]), k != j\)

  • 答案\(ans\): \(min(f[0][j], 1 <= j <= 20)\)

void solve(){
    cin >> n;
    vector<int> a(n);
    vector g(n, vector<int>());
    vector f(n, vector<int>(21, 0));

    for (int i = 0; i < n; i ++)
        cin >> a[i];
    
    for (int i = 0; i < n - 1; i ++){
        int a, b;
        cin >> a >> b;
        a --, b --;
        g[a].eb(b), g[b].eb(a);
    }

    auto dfs = [&](auto self, int u, int v) -> void {
        for (int i = 1; i <= 20; i ++){
            f[u][i] = i * a[u];
            
        }   
            
        for (auto x : g[u]){
            if (x == v)
                continue;
            self(self, x, u);
            for (int i = 1; i <= 20; i ++){
                int mi = 1e18;
                for (int j = 1; j <= 20; j ++){
                    if (i == j)
                        continue;
                    mi = min(mi, f[x][j]);
                }
                f[u][i] += mi;
            }
        }

    };
    dfs(dfs, 0, -1);

    int ans = 1e18;

    for (int i = 1; i <= 20; i ++){
        ans = min(ans, f[0][i]);
    }

    cout << ans << endl;
}

标签:958,int,void,Codeforces,cin,++,vector,Div,fag
From: https://www.cnblogs.com/Sakura17/p/18307068

相关文章

  • Codeforces Round 957 (Div. 3)
    知识点1.几个数相乘时,更小的数增加会比更大的数增加得到的乘积来得大题解A.OnlyPluses1.几个数相乘时,当更小的数增大时,得到的乘积会比更大的数增大来得大,也就是更小的数字权重会比较大,那么在5次+1的过程中,每次找最小值++即可#include<bits/stdc++.h>#defineintlonglon......
  • Codeforces Round 898 (Div. 4)(A~H)
    目录A.ShortSortB.GoodKidC.TargetPracticeD.1DEraserE.BuildinganAquariumF.MoneyTreesG.ABBCorBACBH.MadCityA.ShortSortProblem-A-Codeforces暴力枚举每个位置的交换即可。#include<iostream>#include<algorithm>#include<queue......
  • Codeforces Round 957 (Div. 3)
    题目链接:CodeforcesRound957(Div.3)总结:E不懂,F差一个set去重A.OnlyPlusesfag:枚举B.AngryMonkfag:模拟Solution:分裂的花费为\(a_i-1\),添加的花费为\(a_i\)。C.GorillaandPermutationfag:思维Solution:大于等于\(k\)的数,逆序放在最前面,小于等于\(m\)的数,从最后面......
  • Codeforces Round 958 (Div. 2)补题
    文章目录A题(拆分多集)B题(获得多数票)C题(固定OR的递增序列)A题(拆分多集) 本题在赛时卡的时间比较久,把这题想复杂了,导致WA了两次。后来看明白之后就是将n每次转换成k-1个1,到最后分不出来k-1个1直接一次就能分完,即结果加一;#include<bits/stdc++.h>#definein......
  • CodeForces 1983A Array Divisibility
    题目链接:CodeForces1983A【ArrayDivisibility】思路    按规律可得,当a[i]=i时满足题目要求。代码#include<functional>#include<iostream>#include<algorithm>#include<queue>#include<stdio.h>#include<string>#include<cstring......
  • CodeForces 1983B Corner Twist
    题目链接:CodeForces1983B【CornerTwist】思路    可以发现操作一次,被操作位置的对应每一横行和每一纵行的加减数都是3,所以可以根据网格a和b的横纵状态确定是否通过操作使得网格a到达网格b。代码#include<bits/stdc++.h>usingnamespacestd;#definelllonglo......
  • CodeForces 1992A Only Pluses
    题目链接:CodeForces1992A【OnlyPluses】思路    代码#include<functional>#include<iostream>#include<algorithm>#include<queue>usingnamespacestd;#definelllonglongconstintN=500+10;inta[N];voidsolve(){intn......
  • CodeForces 1992D Test of Love
    题目链接:CodeForces1992D【TestofLove】思路    从起点开始起跳,找出下一个木头的位置,若与当前位置的距离小于等于m,则可以直接跳过去,否则判断当前位置与下一个木头之间有没有鳄鱼,有鳄鱼则不能到达对岸,否则继续查找下一个木头,直到对岸。代码#include<functional>......
  • CodeForces 1992E Novice's Mistake
    题目链接:CodeForces1992E【Novice'sMistake】思路    直接对a,b枚举肯定会超时,因为a,b数数字过大,但是通过结果a*n-b可以发现结果最多为6位数,所以对结果的位数进行枚举,然后枚举a,来计算出b并判断是否符合题意,同时需要去掉b不符合题目的范围的情况。代码#includ......
  • CodeForces - 1485F
    题目大意给定数组\(b\),求有多少\(a\)数组满足\(a_i=b_i\or\\sum\limits_{k=1}^ia_k=b_i\)。分析既然有前缀和,不妨将前缀和计入状态中,设\(dp_{i,j}\)为前\(i\)个前缀和为\(j\)的方案数。考虑两种条件的转移方程。若选第一种,有\(dp_{i,j}=dp_{i-1,j-b_i}\)若......