之前几次的总结忘记写了,这次把之前的能写的都写在一起。
CF题目:
别骂了别骂了,真的很努力的在补题了。
CF分数:
1050
截止2022-05-10
感觉最近在算法方面有点懈怠,然后可能花太多精力在项目上了,结果检查一下发现项目问题有一大堆,最近项目可以先缓缓了,等把项目结构重新构建一下 、细节调整一下、BUG修一下,给看过之后确认没问题了再继续写。
最近把题目好好补一补,CF好好打一打。
接下来是我觉得写得出来的CF题解
具体思路
对于这道题,题目要求通过一系列规定的操作把一串长为n的数组变成单调不减数组,问能不能实现。
即
a[i + 1] >= a[i]
规定的操作是:
选择两个下标i, j,使得a[i] = -a[i], a[j] = -a[j]
即交换i和j下标所在位置的数的符号
要形成单调不减数组,我们可以发现,在一系列操作后,我们可以把数组中的符号任意排列
因此我们只要把原数组中的负号全部移动到左侧,正号全部移动到右侧,最后再遍历判断一下,就可以知道经过一系列操作后能不能形成一个单调不减数组。
题解代码(不最优)
GNU G++20 11.2.0(64 bit, winlibs)#include <bits/stdc++.h> #define ll long long using namespace std; int main() { int t; cin >> t; while(t --) { int n; cin >> n; ll a[n + 1] = {0}; int negative = 0; int positive = 0; for(int i = 0;i < n;i ++) { cin >> a[i]; if(a[i] > 0) { positive ++; } else if(a[i] < 0) { negative ++; } a[i] = abs(a[i]); } for(int i = 0;i < negative;i ++) { a[i] = -a[i]; } bool flag = true; for(int i = 0;i < n - 1;i ++) { if(a[i] > a[i + 1]) { flag = false; break; } } if(flag) { cout << "YES" << endl; } else { cout << "NO" << endl; } } return 0; }
具体思路
这道题目比较简单,就是猫粮、狗粮、通用粮食够不够宠物吃。
思路就是把狗粮和猫粮先全部专项供给,不够的再用通用粮食供给。
最后看看有没有剩下来的宠物还没吃的就可以了
题解代码(不最优)
#include <bits/stdc++.h> #define int long long using namespace std; main() { int t; cin >> t; while(t --) { int a, b, c, x, y; cin >> a >> b >> c >> x >> y; x -= a; y -= b; if(x > 0) { if(c > x) { c -= x; x = 0; } else { x -= c; c = 0; } } if(c > 0 && y > 0) { if(c > y) { c -= y; y = 0; } else { y -= c; c = 0; } } bool flag = true; if(x > 0 || y > 0) flag = false; if(flag) cout << "YES" << endl; else cout << "NO" << endl; } }
具体思路
题目要求我们把一个长为n的数组通过一系列规定的操作变成单调严格递增的,问能不能实现,如果能输出最小操作次数,如果不能则输出-1。
即:
a[i + 1] > a[i]
规定的操作:
选定下标为i的值,对它进行向下取除以2的操作(5 / 2 = 2.5取2,8 / 2 = 4取4)
若要形成严格递增的数组,我们可以这么做:
暴力模拟,从下标n-1开始,对它除以2直到小于i + 1下标值。
注意退出条件,如果发现还没到开头都除到0了,那么它肯定没法形成严格递增的数组的。
题解代码(不最优)
#include <bits/stdc++.h> #define int long long using namespace std; main() { int t; cin >> t; while(t --) { int n; cin >> n; int a[n]; for(int i = 0;i < n;i ++) { cin >> a[i]; } int cnt = 0; for(int i = n - 2;i >= 0;i --) { while(a[i] >= a[i + 1] && a[i] != 0) { a[i] /= 2; cnt ++; } if(a[i] == 0 && a[i] >= a[i + 1]) { cnt = -1; break; } } cout << cnt << endl; } }
具体思路
这道题要找出一串字符中“可疑”的字符数量。
根据题目可知,可疑的人偷走了画,可疑的人可以选择撒谎(1/0/?),而其他人说的都是实话。我解题的办法比较“暴力”。
根据事实逻辑,我们可以分几种情况考虑:
(1) 1110000 [10/01交界类型]
(2) ????? [全问号型]
(3) 1?1??0?0 [1?0模糊边界型]
(4) 0?0??? [0开头型]
(5) ??11 [前导1结尾1型]
(6) ??0?? [模糊夹层0型]
(7) ??1?? [模糊夹层1型]
可知:
(1) 10交界有人说了假话,可疑的人数为2
(2) 不知道谁说了假话,所有人都可疑
(3) 1和0之间以及包含边界区间有人说了假话,可以人数为区间长度
(4) 0开头,无论真话假话他都是唯一嫌疑人
(5) 前面都是真话,最后画不见了,最后说还在的(说是1的)就是唯一嫌疑人
(6) 说0的可以为嫌疑人,其前导的模糊答案也都可以为嫌疑人,长度为0到开头的区间长度
(7) 说1的可以为嫌疑人,其后方的模糊答案也都可以为嫌疑人,长度为1到末尾的区间长度
具体逻辑可以自行分析
题解代码(不最优)
#include <bits/stdc++.h> using namespace std; main() { int t; cin >> t; while(t --) { string str; cin >> str; int len = str.size(); if(len == 1 || str[0] == '0' || str[str.size() - 1] == '1') { cout << "1" << endl; continue; } int f1 = -1, f0 = -1; for(int i = 0;i < len;i ++) { if(str[i] == '1') f1 = i; else if(str[i] == '0' && f0 == -1) f0 = i; } if(f1 == -1 && f0 == -1) { cout << str.size() << endl; } else if(f1 == -1 && f0 != -1) { cout << f0 + 1 << endl; } else if(f1 != -1 && f0 == -1) { cout << str.size() - f1 << endl; } else { cout << f0 - f1 + 1 << endl; } } }
具体思路
这题要求我们把一个长为n的数组通过一系列规定操作变成全部为0的数组,问最少的操作次数。
规定操作:
选择两个下标i,j,进行如下操作
如果a[i] = a[j],则其中一项变为0
如果a[i] = a[j],则a[j] = a[i],反之亦然
对于这个问题,我们分几种情况:
(1) 1 2 3 4 5 全部都不一样
(2) 1 1 3 4 5 有至少1对一样
(3) 0 1 3 4 5 有0,没有相同对
(4) 0 1 1 4 5 有0,有相同对
可知
(1) 操作次数为n + 1
(2) 操作次数为n + 1 - 1 = n
(3) 操作次数为n + 1 - (0的个数 * 1 + 1) = n - (0的个数)
(4) 操作次数为n + 1 - 1 - (0的个数 * 1 + 1) + 1 = n - (0的个数)
这个情况下,只要有0,不论有没有相同对,操作次数都是剩下的不是0的元素的个数,如果没有0有相同对,那么操作次数就是n。
题解代码(不最优)
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while(t --) { int n; bool vis[101]; memset(vis, false, sizeof(vis)); cin >> n; bool same = false; bool haveZero = false; int cnt = n + 1; for(int i = 0;i < n;i ++) { int tmp; cin >> tmp; if(vis[tmp] && !same) { cnt --; same = true; } vis[tmp] = true; if(tmp == 0) { cnt --; haveZero = true; } } if(haveZero && same) cnt ++; if(haveZero ) { cnt --; } cout << cnt << endl; } return 0; }
具体思路
这道题有两个版本,这个是困难版,多个最小连续段数量的输出
这道题要求我们把一串由0和1构成的字符串变成偶数段+偶数段的形式
问要操作的最小字符个数以及最小连续段数量
即
1110001010 -> 1111000000
成双搭配
既然两两搭配,那么我们遍历时就两个两个比较
遇到两个不一样的,就把需要搭改变的字符数量+1。因为变成什么样子不确定,所以我们可以把这两个字符变成通配符(即10,01变成22,记22为通配符),用于后面的最小连续段数量的计算。
在遍历完取得最小改变字符数量后,我们也取得了有通配符的字符串,再遍历一遍获得段个数即可。这里我使用了stack来存不同段,也可以使用其他方法统计。
题解代码
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while(t --) { int n; cin >> n; int len = n; string str; cin >> str; int mincnt = 0; char last = '-'; stack<char> stk; for(int i = 0;i < len;i += 2) { if(str[i] != str[i + 1]) { str[i] = '2'; str[i + 1] = '2'; mincnt ++; } else { if(str[i] != '2') { if(last == '-') { last = str[i]; stk.push(str[i]); } else { if(last != str[i]) { stk.push(str[i]); last = str[i]; } else { } } } } } int pcnt = stk.size(); if(stk.size() == 0) { pcnt = 1; } cout << mincnt << " " << pcnt << endl; } return 0; }
题解结束,接下来是反思和计划
项目方面存在不足:
-
项目文件分包出现问题,分包不明确,出现错误,需要修正
-
客户端和服务端之间的逻辑仍存在部分问题,部分计划存在逻辑问题,需要修改。如客户端的被动接受(BIO)和通信问题。
-
已经实现的部分功能有问题。邮箱注册方面,发送邮箱验证码本地未实现倒计时,邮箱验证码不存在时限限制,需要修改。好友添加方面,接受好友和搜索好友列表存在BUG未刷新,需要修改。
-
数据库建表不完善,先完善数据库表再进行下一步编写。
-
项目面向对象编程没做到位。
算法方面存在不足:
-
过于懈怠,CF比赛刷题和补题不及时、积极性不高,导致水平徘徊不进。
-
补题过于一根筋,题解、答案理解不到位。
其他方面存在不足 :
-
没有规划好时间,时间倾斜不到位。
-
没有计划好工作,资料搜集、归类、学习不到位。
计划:
- 接下来1周解决项目存在问题,主要是结构修改,暂不添加新内容
- 接下来1周把CF好好打打,题目尽快补完,努力提高积极性
- 重新规划时间,合理分配项目和算法的时间投入
- 询问资料,归类资料并学习,根据相关资料推进项目进度
- 学习他人经验,提升工作效率
项目概览: