蓝桥杯第九届c++大学B组详细

本文介绍了编程中的几个技术挑战,包括日期减法实现、进制转换、计算乘积尾零(涉及对2和5的对数),动态规划解决测试次数问题,以及寻找递增三元组和高效日志统计。最后是关于乘积最大值的分类讨论问题。
摘要由CSDN通过智能技术生成

目录

1.第几天

2.明码

3.乘积尾零

4.测试次数

5.递增三元组

6.日志统计

7.乘积最大


1.第几天

 题目解析:这题是不是和以前有点印象,就是日期类但是是日期的减法。

#include <iostream>
using namespace std;

class Date
{
public:    
      Date(int year, int month, int day)
            :_year(year)
            ,_month(month)
            ,_day(day)
            {
                if(!(year >= 0 && month >= 0 && month < 13 && day > 0 && day < getmonthday(year,day)))
                   cout << "非法日期" << endl;
            }


      
      int getmonthday(int year, int month)
      {
          int Month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
          int day = Month[month];

          if(month == 2 && (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
              day++;
          return day;
      }


      bool operator>(const Date& d)const
      {
          if(_year > d._year)
             return true;
          else if(_year == d._year && _month > d._month)
             return true;
          else if(_year == d._year && _month == d._month && _day > d._day)
             return true;
          else
             return false;
      }

      bool operator==(const Date& d)const
      {
           return _year == d._year &&
                  _month == d._month &&
                  _day == d.day;
      }

      bool operator<(const Date& d)const
      {
         return !(*this = d);
      }

      bool  operator>=(const Date& d)const
      {
           return *this > d || *this == d;
      }

      bool operator<=(const Date& d)const
      {
           return !(*this > d);
      }

      bool operator!=(const Date& d)const
      {
           return !(*this == d);
      }

      Date& operator+=(int day)
      {
          if(day < 0)
             return *this -= -day;
          
          _day += day;
          while(_day > getmonthday(year, month))
          {
              day -= getmonthday(year, month);
              _month++;

              if(_month == 13)
              {
                 _month = 1;
                 year++;
              }
          }
          return *this;
      }

      Date& operator+(int day) const
      {
           Date ret(*this);//拷贝构造
           ret += day;
           return ret;
      }

      Date& operator-=(int day) 
      {
           if(day < 0)
              return *this += -day;
           _day = day;
           while(_day <= 0)
           {
               _month--;
               if(_month == 0)
               {
                  _month = 12;
                  _year--;
               }
               _day += getmonthday(_year, _month);
           }
           return *this;
      }

      Date operator-(int day) const
      {
          Date ret(*this);
          ret -= day;
          retuen ret;
      }

      Date& operator++()
      {
          *this += 1;
          return *this;
      }

      Date& operator++(int)
      {
          Date& ret(*this);
          *this += 1;
          return ret;
      }

      Date& operator--()
      {
          *this -= 1;
          return *this;
      }

      Date& operator--(int)
      {
          Date& ret(*this);
          *this -= 1;
          return ret;
      }

      int operator-(const Date& d) const
      [
          Date max = *this;
          Date min = d;
          int flag = 1;
           if(*this < d)
           {
               max = d;
               min = *this;
               flag  = -1;
           }
           int count = 0;
           while(min != max)
           {
                ++min;
                ++count;
           }
           return count * flag;
      ]

private:
      int  _year;
      int  _month;
      int  _day;
};

int main()
{
	Date d1(2000, 1, 1);
	Date d2(2000, 5, 4);
	int count = d2 - d1;
	cout << count << endl;
	return 0;
}

2.明码

 题目解析:看清题目,其实就是进制转换。再将数据是2个字节一起处理是16点阵。

#include <iostream>
#include<bitset>
#include<string>
using namespace std;

int main()
{
    int n, m;
    int len;
    string tmp;
    //因为是16个点阵一个字节8个信息,那么一次就需要两个字节。
    while(cin >> n >> m)
    {
       bitset<8> t;
       t = n;
       tmp = t.to_string();
       len = tmp.size();
       for(int i = 0; i < len; i++)
       {
           if(tmp[i] == '0')
             cout << " ";
           else
             cout << "*";
       }

       t = m;
       tmp = t.to_string();
       len = tmp.size();
       for(int i = 0; i < len; i++)
       {
           if(tmp[i] == '0')
             cout << " ";
           else
             cout << "*";
       }
       cout << endl;
    }
    return 0;
}

3.乘积尾零

 题目解析:如果直接暴力那么绝对会超出范围,可以这么想。看下面的规律

2*5 = 10; 2*1*5*1 = 10      一个2一个5就是一个0

4*25 = 100  2*2*5*5=100

8*125 = 2*2*2*5*5*5 = 1000;

本质就会转化为求取2和5的对数。

int main()
{
	int num[10*10] =
	{ 5650, 4542, 3554, 473, 946, 4114, 3871, 9073, 90, 4329,
		2758, 7949, 6113, 5659, 5245, 7432, 3051, 4434, 6704, 3594,
		9937, 1173, 6866, 3397, 4759, 7557, 3070, 2287, 1453, 9899,
		1486, 5722, 3135, 1170, 4014, 5510, 5120, 729, 2880, 9019,
		2049, 698, 4582, 4346, 4427, 646, 9742, 7340, 1230, 7683,
		5693, 7015, 6887, 7381, 4172, 4341, 2909, 2027, 7355, 5649,
		6701, 6645, 1671, 5978, 2704, 9926, 295, 3125, 3878, 6785,
		2066, 4247, 4800, 1578, 6652, 4616, 1113, 6205, 3264, 2915,
		3966, 5291, 2904, 1285, 2193, 1428, 2265, 8730, 9436, 7074,
		689, 5510, 8243, 6114, 337, 4096, 8199, 7313, 3685, 211};

    int count_2 = 0, count_5 = 0;
	for (int i = 0; i < sizeof(num) / sizeof(int); i++)
	{

		int tmp = num[i];
		while (tmp % 2 == 0)
		{
			count_2++;
		}

		while (tmp % 5 == 0)
		{
			count_5++;
		}
	}
	cout << min(count_2,count_5) << endl;
	return 0;
}

4.测试次数

题目解析:本质是动态规划,dp[i][j]表示i个手机在j层的运气最坏的测试数。如果在第k层手机摔坏,那么就要到下一层进行测试一次,没摔坏就是要到上一层进行测试。状态转移方程就是dp[j][i] = min(dp[j][i],max(dp[j-1][k-1], dp[j][j-k])+1);最后返回dp[3][1000]就是答案。

#include <iostream>
#include<climits>
using namespace std;
//dp[i][j]表示i个手机在j层的运气最坏的测试数。
int dp[5][1007];

int main()
{
    
    for(int i = 1; i <= 3;i++)
    {
       for(int j = 1; j <= 1000; j++)
       {
           dp[i][j] = j;
       }
    }

    //楼层数
    for(int i = 1; i <= 1000; i++)
    {
       //手机数
        for(int j = 2; j <= 3; j++)
        {
           //从摔坏楼层开始走。
           for(int k = 1; k < i; k++)
           {
               dp[j][i] = min(dp[j][i], max(dp[j-1][k-1], dp[j][i - k]) + 1);
           }
        }
    }
    cout << dp[3][1000] << endl;
    return 0;
}

5.递增三元组

题目解析:先将数组进行排序,使得它们变得有序,然后就是利用两个指针进行将a,c数组找到第一个小于b数组的个数,然后将个数相乘就会得到排序的个数。

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

#define N 100010
int n;
int a[N], b[N], c[N];
long long ret = 0;
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for(int i = 1; i <= n; i++)
    {
        cin >> b[i];
    }
    for(int i = 1; i <= n; i++)
    {
        cin >> c[i];
    }

    //排序;
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1); 
    sort(c + 1, c + n + 1);

    int j = 1;
    int k = 1;
    for(int i = 1; i <= n; i++)
    {
        while(j <= n && a[j] < b[i]) j++;//找到第一个数组种第一次大于第二个数组的数;
        while(k <= n && c[k] <= b[i]) k++;//找到第三个数组种第一次大于第二个数组的数;
        ret += (long long) (j - 1) * (n - k + 1);
    }

    cout << ret << endl;
    return 0;
}

6.日志统计

 题目解析:这个题目就是依葫芦画瓢。看代码哦。

#include <iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
using namespace std;

int N, D, K;

struct log
{
  int id, ts;
};

bool cmp(log a, log b)
{
    return a.ts < b.ts;
}

int main()
{
    cin >> N >> D >> K;

    vector<log> logs(N);
    for(int i = 0; i < N; i++)
    {
       cin >> logs[i].ts >> logs[i].id;
    }
    sort(logs.begin(), logs.end(), cmp);

    //记录答案
    set<int> ans;
    //id出现次数
    map<int, int> cnt;
    
    int j = 0;
    for(int i = 0; i < N; i++)
    {
         //时间间隔不大于D.
         while(j < N && logs[j].ts - logs[i].ts < D)
         {
            cnt[logs[j].id]++;//出现次数++
            //并且id数>=k,就记录一下答案。
            if(cnt[logs[j].id] >= K) ans.insert(logs[j].id);
            j++;
         }
         cnt[logs[i].id]--;
    }      
    
    for(set<int>::iterator i = ans.begin(); i != ans.end(); i++)
           cout << *i << endl;
    return 0;
}

7.乘积最大

 题目解析:本题目就是分类讨论,首先将数组元素进行排序,可以分为三种情况,第一就是全选k == n; 那么就直接选择相乘,然后就是其中进行挑选。k < n;也分两种;一种挑选的k为偶数,一种挑选k为奇数。再在这两种情况当中分负数的有全部,以及部分分为偶数个和奇数个,还有全部是正数的。这样就可以编写了。

#include <iostream>
#include<algorithm>
using namespace std;
#define MOD 1000000009;

const int N = 100010;
long long int a[N];
int main()
{
   int n, k;
   cin >> n >> k;
   int flag = 0;//统计负数
   for(int i = 0; i < n; i++)
   {
       cin >> a[i];
       if(a[i] < 0)
         flag++;
   }

   sort(a, a + n);
   long long int ans = 1;//记录乘积答案
   //全部是负数并且k为奇数
   if(k % 2 != 0 && flag == n)
   {
       for(int i = 0; i < k; i++)
       {
           ans = ans * a[n - 1 - i] % MOD;
           ans = ans % MOD;
       }
       cout << ans << endl;
       return 0;
   }

   //奇数选择】最大的先;
   if(k % 2 != 0)
   {
      ans = a[n - 1];
      n--;
      k--;
   }

   int t = 0;
   int left = 0, right = n - 1;
   //左右两边进行选择;
   while(t < k)
   {
        if(a[left] * a[left + 1] >= a[right] * a[right - 1])
        {
             long long tmp = a[left] * a[left + 1] % MOD;
             ans = ans * tmp % MOD;
             ans = ans % MOD;
             left += 2;
             t += 2;
        }
        else
        {
             long long tmp = a[right] * a[right - 1] % MOD;
             ans = ans * tmp % MOD;
             ans = ans % MOD;
             right -= 2;
             t += 2;
        }
   }

   cout << ans << endl;
   return 0;
}

蓝桥杯冲冲冲,加油xdm。

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值