第二十周代码(蓝桥周赛补做)

本文介绍了几个编程算法题目,包括计算阶乘中0的数量、分巧克力的最小子块尺寸、使用二分法解决数学问题以及处理区间覆盖和全排列问题,展示了算法设计与数学思维的结合。
摘要由CSDN通过智能技术生成

2024/02/26        周一

求阶乘

题目链接

【参考代码】

#include <iostream>
using namespace std;
#define ll long long
//N!的末尾有k个0, 0其实是由2*5得到的
//为什么说直接算5就行?
//以10!为例:2,4,6,8,10都可以提供2,5,10可以提供5,5的数量是比2少的
ll numberOfzeros(ll number)
{
    ll result = 0;
    while(number)
    {
        result += number/5;
        number /= 5;
    }
    return result;
}

int main()
{
  // 请在此输入您的代码
  ll k;
  cin>>k;
  ll l = 0, r = 9e18; //1e19不行,爆long long了,所以用9e18次方
  while(l<r)
  {
      ll mid = l+r >> 1;
      if(numberOfzeros(mid) >= k)
        r = mid;
      else
        l = mid+1;  
  } 

  if(numberOfzeros(r) == k)
    cout << r << endl;
  else
    cout << -1 << endl;
  return 0;
}

分巧克力

题目链接

【参考代码】

暴力75%,罗老师代码更简洁一点

#include <iostream>
using namespace std;

int main() //暴力75%,罗老师代码更简洁一点
{
  int n, k;
  int h[100000], w[100000];
  cin>>n>>k;
  for(int i=0;i<n;i++)
  {
      cin>>h[i]>>w[i];
  }
  int maxside = 0, chocolate_count = 0;
  for(int sidelength=2; sidelength<=1e5; sidelength++) //边长
  {
      for(int i=0;i<n;i++)
      {
          chocolate_count += (int)(h[i] / sidelength) * (w[i] / sidelength);
      }
      if(chocolate_count >= k) //巧克力数量大于孩子数,说明够分
      {
          maxside = max(maxside, sidelength); 
      }
      else //巧克力数量小于孩子数,就到极限了
        break;
      chocolate_count = 0;
  }
  //这里不需要-1,因为我们最大边长不是在循环里面输出的,而是通过比较最大值得出的
  if(maxside > 1)
    cout << maxside << endl;
  else
    cout << 1 << endl;
  return 0;
}

罗老师的:👍👍👍

#include<bits/stdc++.h>
using namespace std;
int h[100010],w[100010];
int n,k;
bool check(int d){              //检查够不够分
    int num=0;
    for(int i=0;i<n;i++)  num += (h[i]/d)*(w[i]/d);
    if(num>=k) return true;     //够分
    else       return false;    //不够分
}
int main(){
    cin >>n>>k;
    for(int i=0;i<n;i++)  cin>>h[i]>>w[i];
    int d=1;                    //正方形边长
    while(1){
        if(check(d))  d++;      //边长从1开始,一个个地暴力试
        else          break;
    }
    cout << d-1;
    return 0;
}

2024/02/27        周二

你不干?有的是帕鲁干!【上周算法赛补题重做】

题目链接

【思路】

看了题解直播后,恍然大悟,原来是找规律+数学公式。找到规律这题就已经成功一半了。两个连续正奇数的平方之差其实是8的倍数,现在非常后悔自己没多推一个例子。

⚠️需要注意的是,这题由于数据太大,10^18输入输出时需要使用printf, scanf函数节约时间。使用cin, cout容易超时

【参考代码】

lld表示输入的数据类型为long long

#include <iostream>
using namespace std;

int main()
{
  //符合平方之差就是8的倍数。设a为正奇数(小的),b=a+2
  //x = (b^2)-(a^2)=(b+a)(b-a)
  //代入b=a+2得(2a+2)*2=x  x=4a+4  x/4=a+1
  int t;
  cin>>t;
  for(int i=0;i<t;i++)
  {
      long long x;
      scanf("%lld", &x);
      
      if(x % 8 == 0 && x != 0)
      {
        long long Positive_OddNumber1,  Positive_OddNumber2;
        Positive_OddNumber1 = x / 4 - 1;
        Positive_OddNumber2 = x / 4 + 1;
        
        printf("Yes\n");
        printf("%lld %lld\n", Positive_OddNumber1, Positive_OddNumber2);  
      }
      else
        printf("No\n");
  }
  return 0;
}

等腰三角形【上周算法赛补题重做】

题目链接

【思路】

排序是必须的,之后就是使用双指针来寻找是否符合条件:(两边之和大于第三边)。因为题目是等腰三角形,存一条边就可以了,用的时候*2。

回看我的代码,错的离谱,竟然觉得会有红色和蓝色木棍相等的情况。太局限于样例,而没有顾全大局

【参考代码】

可以从小的数开始找,也可以从大的数开始找。

从小的数开始找需要全遍历一遍红色木棍的red数组

int i = 0, j=0, ans = 0;
  for( ;i<n; i++) //全遍历red
  {
      if(red[i] * 2 > blue[j])
      {
          j++;
          ans++;
      }
  }

从大的数开始找需要全遍历一遍蓝色木棍的blue数组

int a = n - 1; int b = n - 1;
    for (; b >= 0; b--) //全遍历blue
    {
        if (red[a]*2 > blue[b])
            a--, ans++; 
    }

#include <iostream>
#include <algorithm>
using namespace std;

int red[200001], blue[200001];

int main()
{
  int n;
  cin>>n;
  for(int i=0;i<n;i++)
  {
      cin>> red[i];
  }
  for(int i=0;i<n;i++)
  {
      cin>> blue[i];
  }
  //不排倒序
  sort(red, red+n);
  sort(blue, blue+n);
  //找blue数组中最小的,先用最小的。
  int i = 0, j=0, ans = 0;
  for( ;i<n; i++) //全遍历red
  {
      if(red[i] * 2 > blue[j])
      {
          j++;
          ans++;
      }
  }
   //法二:从red最大开始找, 先用blue最大的
/*
   int a = n - 1; int b = n - 1;
    for (; b >= 0; b--) //全遍历blue
    {
        if (red[a]*2 > blue[b])
            a--, ans++; 
    }
*/
  cout << ans << endl;
}

2024/02/28        周三

计算方程【上周算法赛补题重做】

题目链接

【思路】

二分,数学公式

【参考代码】

#include <iostream>
#include <math.h>
using namespace std;

int k, m;

bool check(long long mid)
{
    if(sqrt(mid) + floor( log(mid)/log(k) ) > m)
        return true;
    else
        return false;
}

long long solve()
{
    long long l = 0, r = 2e8; //因为用二分找,答案在10^4,所以r的最大值10^4 * 10^4
    while(l<r)
    {
        long long mid = l+r >> 1;
        if(check(mid))
            r = mid;
        else
            l = mid+1;
    }
    return l;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>k>>m;
        cout << solve() << endl;
    }
}

2024/02/29        周四闰日

程序员闰年小知识:4年一闰,100年不闰。400年闰

分巧克力

题目链接

【参考代码】

100%通过

#include <iostream>
using namespace std;

int n, k;
int h[100000], w[100000];

bool check(int sidelength) //测试二分所求得的边长sidelength
{
    int chocolate_count = 0;
    for(int i=0; i<n; i++)
       chocolate_count += (h[i] / sidelength) * (w[i] / sidelength);
    if(chocolate_count >= k)
        return true;
    else
        return false;
}

//二分法把长度为n的有序序列上O(n)的查找时间,优化到了O(logn)。
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>h[i]>>w[i];

    int l = 1, r = 100005; //1已经试过了
    while(l<r)
    {
        int mid = (l+r+1) >> 1; //加1防止死循环
        //如何判断是否加1
        if(check(mid))
            l = mid;
        else
            r = mid - 1;
    }
    cout << l << endl;
}

2024/3/1        周五

区间覆盖(加强版)

题目链接

【参考代码】

参考罗老师的代码

#include <iostream>
using namespace std;
#include <algorithm>
#define ll long long

struct section{
    ll s;
    ll t;
}a[100001];

bool cmp(section data1, section data2)
{
    return data1.s < data2.s;
}

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i].s >> a[i].t;
    }
    sort(a, a+n, cmp);
    ll maxlength = -1;
    int count = 0;
    for(int i=0;i<n;i++)
    {
        if(a[i].t >= maxlength)
        {
            count += a[i].t - max(maxlength, a[i].s) + 1;
            maxlength = a[i].t + 1;
        }
    }
    cout << count << endl;
}

全排列问题

题目链接

【参考代码】

#include<bits/stdc++.h>
using namespace std;

int n;
int visit[10];    // 访问标记
int a[10];      //需要做全排列的数组
int result[10];      //当前DFS得到的全排列0~9

void dfs(int step) 
{
    if (step == n+1) //从1开始计算, n+1
    {     //已经对n个数做了全排列,输出全排列
        for (int i=1; i<=n; i++)
            printf("%5d",result[i]);
        printf("\n");
        return;            //结束
    }
    
    for (int i = 1; i <= n; i++) //遍历每个a[i],放进全排列中
    {    
        if (visit[i] == 0)// 数字a[i]不在前面得到的排列中
        {   
            result[step] = a[i];  // 把a[i]放进排列
            visit[i] = 1;      // 保存现场:a[i]不能在后面继续用
            dfs(step + 1);     // 继续把后面的数放进排列
            visit[i] = 0;      // 恢复现场:a[i]重新可以使用
        }
    }
}

int main() {
    cin >> n;
    for (int i=1; i<=n; i++)  
        a[i]=i;   //赋值得到n个数
    dfs(1);  //对a[1]~a[n]做全排列
    return 0;
}
  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值