提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
第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 () 二分查找函数的用法