在蓝桥杯结束的第一个周末也是终于有闲暇时间来补补赛题了。虽然上周已经补了一部分。()
不得不说这次的失利很大程度上是由于我的想当然和粗心导致的。(明明题不难但是拿不到分才是最难受的)故借助此篇文章来书写我的得与失和自我感概。
A - 青春常数
题目链接:https://www.luogu.com.cn/problem/P16232
送分题,但是没拿到分。。。
理由是误以为拆分是字符串拆分,导致我的最终答案就是,最后检查的时候也没发现问题。已白给。。。
大致题意:把一个整数拆分成两个数。求满足和的整数对的个数。
思路:只有当取的前半部分是满足的,所以直接用除以再加上即可。(加因为可取)
#include <bits/stdc++.h>
using namespace std;using ll = long long;#define end '\n'typedef pair<int,int> pii;
void solved(){ cout << 2026202520242023LL / 2LL + 1 << '\n';}
int main(){ ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); solved(); return 0;}C - 循环右移
题目链接:https://www.luogu.com.cn/problem/P16234
同样签到,应该是本场唯一确定拿得到满分的了。。。
大致题意:给定一个长度为的数组,对于每个元素,满足。对于数组中任意一个连续子数组,进行一次循环右移得到的新数组都和原来的相同。求满足的数组的个数。
思路:其实也就是题意的转换。对于任意一个子数组要满足循环右移是自己本身的只可能是相同的数字。即,这种。如果有一个数不相同都无法满足题意。所以我们直接求出的结果即可。
这里注意特判时无解,题目样例也可以清晰看到。
#include <bits/stdc++.h>
using namespace std;using ll = long long;#define end '\n'typedef pair<int,int> pii;
void solved(){ int t; ll n, x, y; cin >> t; while(t--){ cin >> n >> x >> y; if(x > y){ cout << 0 << '\n'; } else{ cout << y - x + 1 << '\n'; } }}int main(){ ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); solved(); return 0;}D - 蓝桥竞技
题目链接:https://www.luogu.com.cn/problem/P16235
依旧找规律找错了。。然后自己造的数据也没测出来问题,又痛失一道简单题。。
大致题意:给定一个数组长度为的数组。其中第个位置的选手数量为。需要满足每人组成一个战队,并且队中的每个人都来自互不相同的位置。若能将所有人都分配完并满足条件输出,否则。
思路:由题意可知,满足题意的总人数必须为的倍数(第一个条件),并且每个都不能超过(人数总和 )。(第二个条件)
而这就是上述条件满足的充要条件了。
#include <bits/stdc++.h>
using namespace std;using ll = long long;#define end '\n'typedef pair<int,int> pii;
void solved(){ int t; cin >> t; while(t--){ int n; ll sum = 0; ll ma = 0; cin >> n; for (int i = 1; i <= n;i++){ int x; cin >> x; if(x > ma){ ma = x; } sum += x; } if(sum % 5 == 0 && (ma <= (sum / 5))){ cout << 'T' << '\n'; } else{ cout << 'F' << '\n'; } }}
int main(){ ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); solved(); return 0;}反思:我当时在考场上推出的结论是,但事实上这并不是该题目的充要条件。。这是一个更为严苛的条件。当数组为时,就会输出,但实际上这是可行的一种方案。可惜我在考场上并没有找出这样的反例。。
G - 理想温度
题目链接:https://www.luogu.com.cn/problem/P16238
比较难的一题。需要去优化找贡献的方法。虽然我当时连题目都理解错了(),想当然的以为只是简单的连续子序列,而忽略了序列外的应该有的贡献。
大致题意:给定个或为对应第的传感器的温度示数的数组和。现在要对数组进行一次操作:划定区间,输入一个使得区间内的所有值加上。要求执行完一次操作后最多能使多少个的值等于对应的的值。
思路:首先我们先要将都减去,记录下差值。将差值为(无需操作就已经满足条件)的数量以前缀和的方式来记录。方便后续对操作区间外的满足条件的数量进行计数。然后对于对应的每一个差值我们记录下标并存入中。接着我们遍历的每一个非值,对区间内的和区间外的贡献进行计算(详细看注释),取贡献和的最大值就是结果了。
本题解主要参考了苯环大佬的代码,思路融入了一点个人理解,详细可以看看他站的视频讲解。
#include <bits/stdc++.h>
using namespace std;using ll = long long;#define end '\n'typedef pair<int,int> pii;
ll a[200010];ll pre[200010]; //A数组和B数组差值为0的个数的前缀和
void solved(){ int n; cin >> n; for (int i = 1; i <= n;i++){ cin >> a[i]; } map<int, vector<int>> pos; //记录每个差值的下标 for (int i = 1; i <= n;i++){ int x; cin >> x; a[i] -= x; pos[a[i]].push_back(i); pre[i] = pre[i - 1] + (a[i] == 0); //a[i] = 0时前缀加1 }
int ans = pre[n]; //结果初始化为不进行操作时的总贡献 for(auto & [val, v] : pos){ if(val == 0) continue; //跳过a[i] = 0 int sum = 1, mx = 1; //sum初始化为当前操作区间内的L,即第一个操作数,mx同理 for (int i = 1; i < v.size();i++){ int L = v[i - 1], R = v[i]; int cur = 1 - (pre[R - 1] - pre[L]); //区间内原本为0的值的个数会导致负贡献,需要减去(这里的1是操作后R位置修改为0的一个贡献) sum += cur; if(sum < 1){ //如果贡献小于1就重置操作区间左端点为当前的R,大于等于1就继续叠加,将操作区间的右端R设定到v的下一个元素。 sum = 1; } mx = max(mx, sum); //取sum出现过的最大值。 } ans = max(ans, mx + pre[n]); //更新ans的最大值。mx表示的是操作之后和原来贡献的变化值,故加上不操作时的初始贡献值。 } cout << ans;}
int main(){ ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); solved(); return 0;}小小感概
看了上述题目你可能觉得博主菜飞了(事实上也确实如此),基本没什么难度。
不过剩下的题目其实相对来说更难,不过博主懒得补了()主要还是写写自己的反思。
除去白给报名费的悲伤之外,我也逐渐发掘自己的问题了。我对于题目的建模能力似乎是相对比较差的。这点在之前打比赛的时候经常罚时感觉也能看出来()。以至于我在这次比赛的失利,也很大程度上是因为我依赖于和赛制的实时反馈。而在没有评测机时,面对比较技巧性的题目和简单的样例,我便很容易就出错。唉,只能说还是加训加少了。接下来的学习我应该会针对性的锻炼自己的建模能力,给自己更多独立思考的时间,以求能提高自己的解题的准确度吧。