第26场篮桥月赛

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

第26场篮桥月赛

  • 一、好汤圆(水题)
  • 二、灯笼猜谜
  • 三、元宵分配
  • 四、摆放汤圆
  • 五、元宵交友
  • 六、灯笼大乱斗
  • 总结


#作为大学生参与的第二场竞赛
提示:这里可以添加本文要记录的大概内容:


提示:以下是本篇文章正文内容,下面案例可供参考

一、好汤圆(水题)

输出2025/15的商,太水了

#include <iostream>
using namespace std;
int main()
{
  printf("%d",2025/15);
  return 0;
}

二、灯笼猜谜

要求疲劳度最小,那就让每一次移动的最少,因为要按顺序猜灯谜,所以不用考虑那么多!特别注意超int类型用long long!

#include <iostream>
using namespace std;
int main()
{
  long long n,m;
  cin>>n>>m;
  long long sum=0;
  long long place=1;
  int a,b;
  for(int i=1;i<=n;i++)
  {
    cin>>a>>b;
    if(place<a)
    {
      sum+=a-place;
      place=a;
    }
    else if(place>b)
    {
      sum+=place-b;
      place=b;
    }
    else continue;
  }
  cout<<sum<<endl;
  return 0;
}

用place来记录位置,每输入一个灯谜的信息,进行比较左右范围来找最短需要挪动距离,给计数器sum加上距离,最后输出sum即可。

三、元宵分配

村长老奸巨猾,根本就不想多分汤圆!
任选两碗混合,那肯定有一碗什么都没有!
最后还是选最少的n/碗给小朋友,说明混合出现的空碗还是小孩的!
那么想要最多,最佳策略就是将最少的两碗混合!
这样就导致,其实结果就是sort排序,最小的n/2碗汤圆的累加和!
(其实我考试的时候就是按村长的步骤写的然后红了没分)

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	long long n,k;
	cin>>n>>k;
	long long sum=0;
	int a[100011];
	for(int i=1;i<=n;i++)
	cin>>a[i];
	sort(a+1,a+n+1);
	for(int i=1;i<=n/2;i++)
	sum+=a[i];
	cout<<sum;
	return 0;
 } 

四、摆放汤圆

起初想法是八皇后,结果发现不会写,看题解发现是规律!
1×1的格只有一种情况
2×2的格有两种情况:正方形的两条斜对角线上
3×3的格增加一行一列:(1)如果增加的汤圆正好在对角线上那他可能出现的情况就 等于2×2的数量(2)如果不在对角线上,那么了让它对称,我再拿出一个汤圆让他对称,除去对角线上那一个,还有(3-1)行可以放汤圆,对称再放一个,此时剩余(3-2)×(3-2)的一个矩阵及1×1,可推出a[i]=a[i-1]+(i-1)a[i-2];

#include<iostream>
using namespace std;
int N=1e9+7;
int main()
{
	int t,n;
	cin>>t;
	long long a[1000001];
	a[1]=1;
	a[2]=2;
	for(int j=3;j<=1000000;j++)
		a[j]=(a[j-1]+(j-1)*a[j-2])%N;
	for(int i=1;i<=t;i++)
	{
		cin>>n;
		cout<<a[n]<<endl;
	}
	return 0;
}

模拟根本没看到这道题,第二道题就折了=-=!

五、元宵交友

题上说了熟悉规则,就是看两个人的差能不能超过k,然而1<=k<=n,那我给他排个序,我去找这个序列里面差值大于k的,计数总和不就可以了吗?
普通查找,炸时间了,那就用二分查找了!
知识点:lower_bound()函数找到第一个大于它的数(库自带函数很方便)
por=lower_bound(a+1,a+n+1,a[por]+k)-a
por表示位置坐标,在数组a的(1,n+1)区间找到第一个比por位置上的数大k的数
(及a[por]+k)的坐标,并将他的位置替换给por,然后接着找下一个在(por,n)之间。

#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int main()
{
	ll n,k;
	cin>>n; 
	ll a[n+1];
	for(ll i=1;i<=n;i++)
	cin>>a[i];
	sort(a+1,a+n+1);
	for(ll i=1;i<=n;i++)
	{
		ll pos=1;
		ll num=0;
		while(pos<=n)
		{
			num++;
			pos=lower_bound(a+pos,a+n+1,a[pos]+i)-a;
		}
		cout<<num<<" ";
	}
	return 0;
}

六、灯笼大乱斗

首先师傅是按资质排好序的用a[]数组表示
灯笼亮度用b[i]表示,由题要求可知
a[1]+max(b[1],b[2])<a[2]+min(b[1],b[2])
a[2]+max(b[2],b[3])<a[3]+min(b[2],b][3])
问题转换一下
a[2]-a[1]>max(b[1],b[2])-min(b[1],b[2])及a[2]-a[1]>abs(b[2]-b[1])
abs()是求绝对值的函数
那我们现在来思考
如果a[1],a[2]满足,a[2],a[3]满足那么a[1]a[3]是否也能满足呢
a[2]-a[1]>abs(b[2]-b[1])
a[3]-a[2]>abs(b[3]-b[2])
推出a[3]-a[1]>abs(b[3]-b[2])+abs(b[2]-b[1])
(1)|1-2|+|2-3|=|1-3|
(2)|3-2|+|2-1|=|3-1|
(3)|2-1|+|1-3|>|2-1+1-3|
举例可推出
abs(b[3]-b[2])+abs(b[2]-b[1])>=abs(b[3]-b[1])
那么 a[3]-a[1]>abs(b[3]-b[2])+abs(b[2]-b[1])
一定满足a[3]-a[1]>abs(b[3]-b[1])
及出现传递,那么只要任意两个相邻的师傅满足,那么区间内任意两个师傅都满足
题目要求求的是区域个数
又要开始烧脑
区域个数怎么求?
那如果我已知区域长度我怎么求区域个数
两个,两个一组
三个,三个一组
那不就是集合子集个数的求法
假设集合有n个数那就有n*(n-1)/2个子集(除去空集)
那么设定一个计数器k
从左到右开始遍历师傅和灯笼
用k来记录连续满足条件的师傅的个数
当不连续时我就把k记录的满足条件的师傅的组合数加起来
将k重置不就实现区域个数的计算了
最后循环结束k如果没有重置那么说明最后一段连续的满足条件的区域还没有加
再进行一次单独的加即可求出

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	long long n;
	cin>>n;
	long long k=1;
	long long sum=0;
	long long a[n+1],b[n+1];
	for(long long i=1;i<=n;i++)
		cin>>a[i];
	for(long long i=1;i<=n;i++)
		cin>>b[i];
	for(long long i=2;i<=n;i++)
		if(a[i]-a[i-1]>abs(b[i]-b[i-1]) )
		{
			k++;
		}
		else 
		{
			sum+=(k-1)*k/2;
			k=1; 
		}
	if(k!=1)
	sum+=k*(k-1)/2;
	cout<<sum;
	return 0;
 } 

总结

思维实在是太牛了,根本想不到
我是菜鸡,纯看别人代码自己理解的
lower_bound () 二分查找函数的用法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值