蓝桥杯热身赛题解
一、填空题
三角回文数
标签:枚举
思路:枚举阶乘数并判断是否是回文数
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int i = 1; // 阶乘数
while(true)
{
int sum = (1 + i) * i / 2, t = sum;
vector<int> v;
// 存每一位的数字,方便判断是否是回文
while(t) v.push_back(t % 10), t /= 10;
int l = -1, r = v.size();
while(l ++, r --, l <= r)
if(v[l] != v[r]) break;
if(r < l && sum > 20220514)
{
cout << sum ;
return 0;
}
i ++;
}
return 0;
}
奇怪的捐献
标签:DFS
思路:可使用的金额总类数最多只有7种,因为 7 8 7^8 78就已经超过100万了,所以我们可以枚举每个种类的金额的份数,时间复杂度为16807。
#include <iostream>
using namespace std;
int res = 0x3f3f3f3f;
// 钱数,选择个数,当前要选的是多少一份
void dfs(int money, int cnt, int num)
{
if(money == 0)
res = min(cnt, res);
if(num > money) return;
// 枚举每份选择0~5个
for(int i = 0; i <= 5; i ++)
if(money >= i * num)
dfs(money - i * num, cnt + i, num * 7);
}
int main()
{
dfs(1000000, 0, 1);
cout << res << endl;
return 0;
}
二、编程题
刷题统计
标签:暴力
思路:太简单了,不解释了(⋟﹏⋞)
#include <iostream>
#include <math.h>
#define LL long long
using namespace std;
int main()
{
LL a, b, n;
cin >> a >> b >> n;
LL t = 5 * a + 2 * b;
LL day = n / t * 7;
n %= t;
if(n > 5 * a)
{
n -= 5 * a;
cout << day + 5 + (LL)ceil(n * 1.0 / b) << endl;
}
else cout << day + (LL)ceil(n * 1.0/a) << endl;
return 0;
}
阶乘的和
标签:贪心
思路:找最小的阶乘,不断用当前的阶乘合成更加大的阶乘,直到合成不了为止, 此阶乘模所有的阶乘都是0所以就是答案。
eg: 3!有4个,4!有4个,最终合成一个5!
3!有5个,4!有4个,最终只能是3!,因为用去4个3!合成了一个4!,此时还余下一个3!那此时最小的阶乘还是3!,因此答案不变。
#include <iostream>
#include <map>
#include <algorithm>
#define LL long long
using namespace std;
int n;
int ans = 2e9;
map<int, int> cnt;
int main()
{
cin >> n;
for(int i = 0; i < n; i ++ )
{
int x; cin >> x;
cnt[x] ++;
ans = min(ans, x); // 找最小的阶乘
}
// 合成更大的阶乘
while(cnt[ans] % (ans + 1) == 0){
cnt[ans + 1] += cnt[ans] / (ans + 1);
ans ++;
}
cout << ans;
return 0;
}
交换瓶子
标签:图论,环,置换群,贪心
思路:将给定的数组中的每一个元素值与其下标值连一个边,然后将数组中与当前这个下标值相等的元素值做为下一个目标,重复这样的操作,直到所有数都被用到,就可以得到若干个环,
每一个环的含义可以这样理解-----------设两个点u和v,环中两个点之间的关系就是u能到v,环中每条边的意思就是u这个值的位置应该在v值所在位置,例如:第一环,2能到1,2这个值的位置就在1这个值所在位置。按照这样的定义,我们的目标就是将所有的环变成n个自环,也就是每个值都在它应该在的位置。每一次的交换,等价于将1个环拆成2个环,每次操作都能增加一个环,为什么这里就不做解释了,自己手写模拟一下,就可以看出来了。答案就是" n - 当前环的个数"
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int main()
{
int n; cin >> n;
int res = 0;
for(int i = 1; i <= n; i++)
cin >> a[i];
for(int i = 1; i <= n; i++)
{
while(a[i] != i)
{
res ++;
swap(a[i], a[a[i]]);
}
}
cout << res << endl;
return 0;
}
重新排序
标签:差分,贪心
思路:利用差分区间修改的特性,统计出每个位置上的数字被加了几次,最佳的排序方式就是次数最多的的位置上放数字最大的值。
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int N = 100010;
int f[N], g[N];
int main()
{
int n; cin >> n;
for(int i = 1; i <= n; i++)
cin >> f[i];
int m; cin >> m;
while(m--)
{
int l, r;
cin >> l >> r;
g[l] ++; g[r + 1] --;
}
LL res1 = 0, res2 = 0;
for(int i = 1; i <= n; i++)
{
g[i] += g[i-1];
res1 += (LL)g[i] * f[i];
}
sort(g + 1, g + n + 1, greater<int>());
sort(f + 1, f + n + 1, greater<int>());
for(int i = 1; i <= n; i++)
res2 += (LL)g[i] * f[i];
cout << res2 - res1 << endl;
return 0;
}
纪念碑谷
标签:二分,推公式
思路:这里只讲二分,推公式不好理解,有兴趣自己研究吧。二分查找答案,然后按顺序遍历数组看是否满足条件,通过对题目给出的公式进行等价变换可以得到 E = 2 ∗ E − H [ i ] E=2*E-H[i] E=2∗E−H[i],二分边界最小值就是0, 最大值就是100000,当答案为100000时必然成立,因为根据题意可以推出取最大值时,当前的E是恒大于等于所有的值的那么它的值就只增不减,就不会小于0,所以肯定是合法的答案。
#include <bits/stdc++.h>
using namespace std;
int n;
int a[100000];
bool check(int e)
{
for(int i = 0; i < n; i ++ )
{
e = 2 * e - a[i];
if(e >= 100000) return true;
if(e < 0) return false;
}
return true;
}
int main()
{
cin >> n;
for(int i = 0; i < n; i ++ )
cin >> a[i];
int l = 0, r = 100000;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << r;
}
探险取宝
标签:DP
思路:dp[i, j, k, v]表示走到 (i, j)这个位置拿走了k件物品并且物品的最大值为v的方案集合,状态转移分两种情况:
1、当前这个物品不拿,状态从上一个位置拿了k件物品最大值为v的状态转移过来,即 d p [ i , j , k , v ] + = d p [ i − 1 , j , k , v ] + d p [ i , j − 1 , k , v ] dp[i, j, k, v] += dp[i - 1, j, k, v] + dp[i, j - 1, k, v] dp[i,j,k,v]+=dp[i−1,j,k,v]+dp[i,j−1,k,v];
2、当前这个物品拿,此时状态中的v就必须是和( i, j )位置上的物品值一样才可以更新,状态就是由上一个位置拿了k - 1件物品最大值小于v的状态转移过来, 即 d p [ i , j , k , v ] + = ∑ v = 0 a ( i , j ) − 1 d p [ i − 1 , j , k − 1 , v ] + d p [ i , j − 1 , k − 1 , v ] dp[i, j, k, v] += \sum_{v=0}^{a_(i, j)-1}dp[i - 1, j, k - 1, v] + dp[i, j - 1, k - 1, v] dp[i,j,k,v]+=∑v=0a(i,j)−1dp[i−1,j,k−1,v]+dp[i,j−1,k−1,v];
#include <bits/stdc++.h>
using namespace std;
const int N = 55, MOD = 1000000007;
int n, m, k;
int w[N][N];
int f[N][N][13][14];
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
cin >> w[i][j];
w[i][j] ++; // 值有0,在DP的定义中0是用来初始化的
}
f[0][1][0][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
for(int u = 0; u <= k; u ++)
for(int v = 0; v <= 13; v ++)
{
int &val = f[i][j][u][v];
val += (f[i - 1][j][u][v] + f[i][j - 1][u][v]) % MOD;
if(u > 0 && v == w[i][j])
{
for(int c = 0; c < v; c ++)
{
val = (val + f[i - 1][j][u - 1][c]) % MOD;
val = (val + f[i][j - 1][u - 1][c]) % MOD;
}
}
}
int res = 0;
for(int i = 0; i <= 13; i ++) res = (res + f[n][m][k][i]) % MOD;
cout << res << endl;
return 0;
}