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

Educational Codeforces Round 164 (Div. 2)

时间:2024-04-29 12:12:13浏览次数:31  
标签:Educational mf int cin long 164 Div mod define




A - Painting the Ribbon

难度: ⭐⭐

解题思路

先看特殊情况, 如果m为1肯定不行, n小于等于k也不行; 我们可以换位思考, 如果Alice用了x种颜色, Bob想把其染为同一种颜色, 肯定要先找出这x种颜色中染色区域最多的那一种, 然后把其他区域的颜色换成该颜色, 这样才是最优策略, 所以相应的Alice就要阻止这种最优策略, 也就是使每种颜色的染色区域尽可能的少, 也就是有尽可能地多用颜色; 最后看看Bob用最优策略是否可以实现;

神秘代码

#include<bits/stdc++.h>
#define int unsigned long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 131;
typedef pair<int, int> PII;
int n, m, k;
bool check(){
    if(n <= k) return false;
    if(m == 1) return false;
    int x = n / m + (n % m != 0);
    if(k >= n - x) return false;
    return true;
}
signed main(){
    IOS;
    int T;
    cin >> T;
    for(int i = 1; i <= T; i++){
        cin >> n >> m >> k;
        if(check()) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
	return 0;
}




B - Make It Ugly

难度: ⭐⭐

解题思路

根据题意我们可以得出漂亮数组的几个性质: 一是漂亮数组的第1个元素和最后1个元素一定相同, 我们设为x; 二是漂亮数组中不为x的元素一定是单独出现, 即其前后都是x;
根据这两个性质, 我们可以知道漂亮数组就是由若干个连续的值x的序列组成, 它们之间由不为x的元素分割: xxxaxxxxbxxxxcx; 而且要做的就是破坏这条性质, 也就是删除其中一个连续的值为x的序列, 所以找出其中最短的删去就可以了;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k;
int p[N];
signed main(){
    IOS;
    int T;
    cin >> T;
    while(T--){
        cin >> n;
        for(int i = 1; i <= n; i++){
            cin >> p[i];
        }
        int res = inf;
        int num = 0;
        bool f = true; 
        for(int i = 1; i <= n; i++){
            if(p[i] != p[1]){
                res = min(res, num);
                num = 0;
            }
            else num++;
        }
        if(num) res = min(res, num);
        if(res == n) res = -1;
        cout << res << endl;
    }
	return 0;
}




C - Closest Cities

难度: ⭐⭐⭐

解题思路

一个比较明显的贪心问题, 对于两个长度相同的数a和b的乘积, 当a和b越相近时乘积越大; 根据这条性质我们可以先从左往右开始找到第一个两者数字不相同的位置, 此时这个位置上的数可以决定两者到底谁大谁小; 确定完之后, 我们之后的策略就是让小的数变大, 大的数变小; 毕竟往后的数再怎么变也不会改变两者的大小关系, 只会让a和b越接近;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k;
int p[N];
signed main(){
    IOS;
    int T;
    cin >> T;
    while(T--){
        string s1, s2;
        cin >> s1 >> s2;
        int f = 0;
        for(int i = 0 ; i < s1.size(); i++){
            if(f == 0){
                if(s1[i] > s2[i]) f = 1;
                else if(s1[i] < s2[i]) f = 2;
            }
            else{
                if(f == 1) 
                    if(s1[i] > s2[i]) swap(s1[i], s2[i]);
                else
                    if(s1[i] < s2[i]) swap(s1[i], s2[i]);
            }
        }
        cout << s1 << endl << s2 << endl;
    }
	return 0;
}




D - Colored Balls

难度: ⭐⭐⭐⭐

解题思路

我感觉这题最难的是要想到用dp...而且题面也很难读懂... 因为n的范围是5000, 所以我们肯定没法遍历所有分组, 所以可以考虑递推; 递推的话要先找规律, 我们观察样例可以发现, 假设有一个分组中有x个数字, 其中最大的数字是maxn, x个数字总和为sum; 如果maxn大于等于其他数字的和(sum - maxn), 那么这个分组的值就是maxn; (也就是让其他数字都和maxn组合); 如果maxn小于其他数字的和, 那么答案就是sum / 2上取整; (就是两两组合);
根据这个规律我们发现maxn和sum可以直接代表整个分组, 也就是说我们不用具体知道这x个数都是多少; 而且题目范围也提示我们sum一定不大于5000; 那么我们就可以直接开一个二维的状态表示dp[i][j]表示最大值为i, 总和为j的分组有多少个;
这样会有一个问题, 状态转移时最多是O(n2)的复杂度, 但是我们有n, max, sum三个变量需要遍历, 所以要优化掉一维; 这里我们可以先把输入进行从小到大排序, 这样我们遍历到的p[i]就一定是此时的最大值, 之前所有处理好的状态的max都比p[i]小, 那么我们就不用管之前的max是多少了, 一股脑全加上就行, 开一个数组mf[i]表示在此之前sum为i的分组有多少个, 其更新为mf[j + p[i]] = mf[j + p[i]] + mf[j]; 这样就把max优化掉了; 最后的状态转移就是dp[p[i]][j + p[i]] = dp[p[i]][j + p[i]] + mf[j]; 其中j是遍历的sum;
最后我们遍历最大值和总和, 按照之前找的规律进行求解就可以了;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e4 + 10, mod = 998244353;
int dp[N][N];
int mf[N];
int n;
int p[N];
signed main() {
    cin >> n;
    mf[0] = 1;
    for(int i = 1; i <= n; i++) {
        cin >> p[i];
    }
    sort(p + 1, p + 1 + n);
    for(int i = 1; i <= n; i++){
        for(int j = 5000; j >= 0; j--){
            dp[p[i]][j + p[i]] = (dp[p[i]][j + p[i]] + mf[j]) % mod;
            mf[j + p[i]] = (mf[j + p[i]] + mf[j]) % mod;
        }
    }
    int res = 0;
    for(int i = 0; i <= 5000; i++){
        for(int j = 0; j <= 5000; j++){
            if(i >= j - i){
                res = (res + (dp[i][j] % mod * i) % mod) % mod;
            }
            else{
                int x = (j + 1) / 2;
                res = (res + (dp[i][j] % mod * x) % mod) % mod;
            }
        }
    }
    cout << res ;
    return 0;
}




E - Chain Reaction

难度: ⭐⭐⭐⭐

解题思路

我们开一个数组h[i]表示第i个怪兽是否存活, 为1则存活; 我们攻击的目标就是一个连续的1的序列; 如果此时有x个连续的1的序列, 那么我们至少要攻击x次; 所以我们开一个数组f[i]表示用伤害为i攻击一次后还剩下几个连续的1的序列, f[0] = 1;
更新f[i]时我们发现是会有继承关系的, 如果没有血量为i的怪兽, 那么用i攻击和用i - 1攻击效果是一样的, 所以f[i] = f[i - 1]; 如果有血量为i的怪兽, 我们可以只处理这些怪兽, 因为其他怪兽的状态一定和f[i - 1]时是一样的, 所以可以在f[i - 1]的基础上进行修改; 如果第j个怪兽血量为i, 我们需要去检查第j - 1和j + 1个怪兽的状态, 如果这两个都存活, 那么该连续的1的序列会被一分为二, 连续的1的序列数量+1; 如果都不存活, 说明j自己就是一个连续的1的序列, 被杀后连续的1的序列会-1; 其他情况数量不变;
最后处理答案时, 因为f[i]是攻击一次后的情况, 如果攻击后还有存活的那么就得再攻击一次, 相当于f[i + i]; 所以循环时j += i

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k;
int p[N], f[N], h[N];
vector<int> v[N];
signed main(){
    IOS;
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> p[i];
        m = max(p[i], m);
        h[i] = 1;
        v[p[i]].push_back(i);
    }
    f[0] = 1;
    for(int i = 1; i <= m; i++){
        f[i] = f[i - 1];
        for(int x : v[i]){
            if(h[x - 1] && h[x + 1]) f[i]++;
            if(h[x - 1] == 0 && h[x + 1] == 0) f[i]--;
            h[x] = 0;
        }
    }
    for(int i = 1; i <= m; i++){
        int res = 0;
        for(int j = 0; j <= m; j += i){
            res += f[j];
        }
        cout << res << ' ';
    }
	return 0;
}

标签:Educational,mf,int,cin,long,164,Div,mod,define
From: https://www.cnblogs.com/mostimali/p/18165389

相关文章

  • Manthan, Codefest 18 (rated, Div. 1 + Div. 2) D. Valid BFS?
    题意:给一个树和一个bfs序,并保证从节点1出发,判bfs序是否合法。思路:双指针,在bfs序上从左往右遍历。慢指针指向当前节点u,快指针指向当前节点应该访问的节点的位置。然后设两个集合,一个集合存储在当前节点上应该访问的节点,另一个存储在当前节点上实际访问的节点,然后遍历即可。总结:......
  • Educational Codeforces Round 164
    A-C简单数学题先跳过了,E题水平有限,暂时写不出来下面是D的题意ColoredBall(https://codeforces.com/contest/1954/problem/D)看题目,对于初学者来说,可能不知道使用DP怎么联想到DP的可能还是经验问题下面是个人对题目的拙见题目要求所有幂集组合里需要至少需要多少个二元对才......
  • Codeforces Round 941 (Div. 1) 题解(A-C)
    比赛链接:https://codeforces.com/contest/1965官解链接:https://codeforces.com/blog/entry/128914比较手速的一场,C与D之间出现了较大的gifficultygap。所幸C题猜得比较快(虽然证明其实比较难),最终rank190,performance2525,成功压线拿下Grandmaster。cpchenpi,堂堂上红!......
  • Codeforces Round 941 (Div. 2)
    A.CardExchange贪心。如果有某个数出现\(k\)次及以上,则通过操作使其数量变为\(k\),再变为其他出现过的数,则会增加至至少\(k\)个,一直进行如上操作,可以发现数组最终只剩\(k-1\)个数;否则为\(n\)。#include<bits/stdc++.h>usingnamespacestd;#definecctieios::......
  • Codeforces Round 941 (Div. 2) D
    好坐牢的一次div2ABC是速通的,结果cf的pretest太弱了。。然后我这次因为想快点,没有再去好好顺一遍思路,状态又不太好,写了一个好简单的错,结果过了。导致我被hack了,爆掉100分。好烦。主要说说这个D。现在能够从算式的层面上理解了这个做法的正确性,就是把二进制位的数字放进去,然后......
  • js调整div顺序
    js调整div顺序并保留div原有事件等<divclass="my_tabs"><divclass="el-tabs__nav-scroll"><divclass="el-tabs__nav"><divclass="el-tabs__itemis-active">AAAA</div><d......
  • Codeforces Round 936 (Div. 2)
    A考虑有\(x\)个数与中位数相同,且在中位数之后,则答案为\(x+1\)(+1是因为中位数本身)。B明显的,每次操作序列的最大子段和。那么操作完以后,继续操作这个区间即可,相当于每次翻倍。假设原序列最大子段和为区间\([l,r]\),则答案为:\[sum(1,n)-sum(l,r)+sum(l,r)\times2^k\]记......
  • Codeforces Round 931 (Div. 2) D2
    挺简单的题目,就是一个普通博弈论套了一个交互的皮。。。但是恶心的就是,交互的皮是真难顶啊,什么sb玩意,我因为爆了int一直给我现实TLEontest1,这我怎么调?不得不说,交互题和普通的题目真是差别太大了,就评测这一块,返回的消息完全无法给我有效的指导。。然后我就直接坐大牢。要是这......
  • Codeforces Round 939 (Div. 2) E1-E2
    CodeforcesRound939(Div.2)E1.Nenevs.Monsters(EasyVersion)题意:有n个怪物,能量等级为\(a_i\),现在可以使用一种法术,使第1个怪物攻击第2个怪物,第2个怪物攻击第3个怪物……第n个怪物攻击第1个怪物,当能量等级为x的怪物攻击能量等级为y的怪物时,怪物y->max(y-x,0),在经过\(1......
  • Codeforces Round 892 (Div. 2) E
    E的话一眼dp,然后观察一下方程,\(f[i][j]表示前i个位置已经选了长度为j的区间,且第i个位置已经被选上时,能够获得的最大值\)\[f[i][j]=\displaystyle\max_{1\leqk\leqmin(i,j)}(f[i-k][j-k]+calc(i-k+1,j))\\calc(l,r)=|b_l-a_r|+|b_r-a_l|\]这样的dp是\(O(n^2k)\)的,而\(1\leqk......