前几天,蓝桥杯国赛的成绩出了,拿了国三,有点小遗憾但也在预料之内吧
不过成绩出了不代表都结束了,还是要复盘,就从省赛开始吧,省赛我拿了是省一,但是回过头来才发现其实还是有不少不会的地方,所以来总结一下吧,这次就不发截图了,直接给洛谷上的链接吧
由于 2026202620262026 的二进制有 51 位,且一个均衡数的二进制长度必须是偶数,故我们只需要构造二进制为 50 位的最大的均衡数,以及二进制为 52 位最小的均衡数。
想要最大我们就要让尽量让高位是 1,低位是 0。想要最小我们就要让尽量让高位是 0,低位是 1。但最高位不能为 0。所以我们只要让最高位是 1,后面跟 26 个 0,最后再跟 25 个 1 就行。
cpp
#include<bits/stdc++.h>
using namespace std;
int main()
{
cout<<2251799847239679<<endl;
return 0;
}
这个也比较简单,签到题吧
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL l,t,v;
int main()
{
int n;
cin>>n;
while(n--)
{
cin>>l>>t>>v;
LL s=t*v*2;
l-=s;
cout<<l/2+l%2<<endl;
}
return 0;
}
这个就是比较经典的二分嘛
cpp
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long LL;
LL a[N];
LL n,k;
bool check(int x)
{
LL res=0;
for(int i=1;i<=n;i++)
{
res+=a[i]/x-1+(a[i]%x!=0);
}
return res<=k;
}
int main()
{
cin>>n>>k;
LL l=0,r=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
r=max(r,a[i]);
}
LL ans=-1;
while(l<=r)
{
//cout<<l<<' '<<r<<endl;
LL mid=l+r>>1;
if(!check(mid))
{
l=mid+1;
}
else
{
ans=mid;
r=mid-1;
}
}
cout<<ans<<endl;
return 0;
}
这个题,我一开始以为挺简单,以为就是个简单贪心,刚才做了一下才发现是比赛时做错了,这是一个数学问题
首先如果 w 不是 c 的倍数肯定 −1,否则令 x=cw。
如果 1+2+⋯+n=2n(n+1)<x,也是无解。
如果 w=0,答案是 0。(赛时代码好像没考虑这个,寄)
否则,下面证明答案最多是 2。
由于 2n(n+1)≥x,因此一定存在一个 1≤m<n,使得:
- 1+2+⋯+m=2m(m+1)≤x;
- 1+2+⋯+(m+1)>x。
我们可以证明 y=1+2+⋯+(m+1)−x=(m+1)−x−(1+2+⋯m)≤(m+1),我们把 (m+1) 补上,再把 y 删去,最多两个区间。
所以答案不是 1 就是 2。开 map 记录一下前缀和,即可判断一个区间是否可行,可行则为 1,否则为 2。
cpp
#include <iostream>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int N, C;
long long W;
cin >> N >> C >> W;
// 边界1:不需要读取
if (W == 0) {
cout << "0\n";
continue;
}
// 边界2:无法整除C,无解
if (W % C != 0) {
cout << "-1\n";
continue;
}
long long x = W / C;
long long total = (long long)N * (N + 1) / 2;
// 边界3:总和不足,无解
if (x > total) {
cout << "-1\n";
continue;
}
// 双指针判断是否存在单个连续区间和为x
long long sum = 0;
int l = 1;
bool found = false;
for (int r = 1; r <= N; ++r) {
sum += r;
while (sum > x) {
sum -= l;
l++;
}
if (sum == x) {
found = true;
break;
}
}
cout << (found ? 1 : 2) << '\n';
}
return 0;
}
考虑使用动态规划。
- 状态定义: fi 表示送 i 单所需的时间;
- 状态转移: fi←fj+ci−j+x,其中 ci 表示单个交通工具送完 i 单所需的最短时间,j 是枚举的单数;
- 最终答案:fn。
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, x, f[5005], c[5005];
signed main() {
memset(c, 0x3f, sizeof c);
cin >> n >> m >> x;
for (int i = 1, a, b; i <= m; ++i) {
cin >> a >> b;
for (int j = 1; j <= n; ++j) {
c[j] = min(c[j], j * a + j * (j - 1) / 2 * b); // 预处理
}
}
for (int i = 1; i <= n; ++i) {
f[i] = c[i];
for (int j = 1; j < i; ++j) {
f[i] = min(f[i], f[j] + c[i - j] + x); // 状态转移
}
}
cout << f[n];
return 0;
}
好的,现在比赛中黄题难度及以下,以及我比赛时会的题目就已经说完了,这些题如果都拿下其实就能稳稳省一了,我现在回过头来发现,我当时应该就是A,C,D,F题做对了,G暴力得了一半分,拿了省一