蓝桥杯热身赛题解

蓝桥杯热身赛题解

一、填空题

三角回文数

标签:枚举

思路:枚举阶乘数并判断是否是回文数

#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=2EH[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[i1,j,k,v]+dp[i,j1,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[i1,j,k1,v]+dp[i,j1,k1,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;
}
  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值