河南萌新联赛2025第(六)场:郑州大学

目录

总结一下,暑假的最后一场萌新联赛,打的一般,虽然a了5道题,但罚时太高了,这点也跟前面的状态有关,前两个小时我都是很落后的,状态很不好,简单的签到题也卡了半天。。。后面慢慢清醒了,能做出来的都做了,最后5min的时候还a了一道题,不枉费我改了又改。暑假集训的这一个多月,也是越来越松懈怠慢,慢慢的没有了学习的激情,可能是要学的东西越来越难了,或者是快开学了,所以最后坚持这几天了,加油↖( ^ ω ^ )↗

L-整数商店的购物之旅

题目来源

解题思路

这道题很简单,但一开始没有思路,想偏了就越想越复杂。所以一开始的思考方向还是很重要的,这道题N的范围只有1e9,而且给了你一个式子,且未知数只有N,那就很显然了,能购买到的最大整数N,也就是查找最大的满足<=X,即可。所以不难想到用二分来查找这个数。

AC代码

cpp 复制代码
int a,b,x;
int check(int mid)
{
	if(a*mid+b*((int)log10(mid)+1)<=x)
	return 1;
	else
	return 0;
}
void solve()
{
	cin>>a>>b>>x;
	int l=0,r=1e9,f=0;
	while(l<r)
	{
		int mid=(l+r+1)/2;
		if(check(mid))
		{
			f=1;
			l=mid;
		}
		else
		r=mid-1;
	}
	if(!f)cout<<0<<endl;
	else
	cout<<l<<endl;
}

E-数字支配

题目来源

解题思路

其实就是让我们输出【1,n】之间的字典序最大的序数的序列。可以想到,一定是让9开头最好,所以只需要构造一个字符串,使他的长度是原字符串长度-1,并且由9填充。这样就能保证字符即不超过n又是字典序最大的。但是有一种特殊情况,那就是如果出现91,993,9998这样的数字,其实输出原字符串是更优的,所以只需要再比较一下构造的这个字符s1和原字符s的大小(按字典序比较),如果s>s1就输出s,否则输出是s1.

AC代码

cpp 复制代码
void solve()
{
	cin>>s;
	int n=s.size();
	if(n==1)
	{
		cout<<s<<endl;
		return ;
	} 
	string s1;
	for(int i=1;i<n;i++)
	s1+='9';
	if(s1<s)
	cout<<s<<endl;
	else
	cout<<s1<<endl;
}

I-外卖大战

题目来源

解题思路

这道题没什么方法,按照题目的意思去模拟,注意好关键点就好,可以用ABC记录优惠力度,A1,B1,C1记录记录订单数量,s1,s2,s3记录没有选择的连续人数,然后按要求遍历就行。

AC代码

cpp 复制代码
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	int A=0,B=0,C=0,s1=0,s2=0,s3=0,A1=0,B1=0,C1=0;
	for(int i=1;i<=n;i++)
	{
		if(A>=a[i])A++,A1++,s1=0,s2++,s3++;
		else if(A<a[i]&&B>=a[i])B++,B1++,s2=0,s1++,s3++;
		else if(A<a[i]&&B<a[i]&&C>=a[i])C++,C1++,s3=0,s1++,s2++;
		else s1++,s2++,s3++;
		if(s1>=3)A+=2,s1=0;
		if(s2>=3)B+=2,s2=0;
		if(s3>=3)C+=2,s3=0;
	}
	cout<<A1<<" "<<B1<<" "<<C1<<endl;
}

K-还在分糖果!

题目来源

解题思路

拿走了所有包含数字7的数字,那么说明1~10中,只包含9个数字,10 ~ 20中只包含9个数字...不难想到看作九进制来计算,每个数的9进制数,不就是拿走7后的数的进位方式吗,但是要注意的是,9进制转换时,n%9一定只包含数字0 ~ 8,但我们要拿走的数字是7,那么影响的是7之后的数字,所以如果a=n%9>=7的话要将结果+1,通过样例也可以很容易的看出来。

AC代码

cpp 复制代码
void Jin(int n)
{
	string s;
	while(n)
	{
		int a=n%9;
		if(a>=7)a++;
		s+=(a+'0');
		n/=9;
	}
	reverse(s.begin(),s.end());
	cout<<s<<endl;
}
void solve()
{
	cin>>n;
	Jin(n);
}

D-穿过哈气之门

题目来源

解题思路

这道题让求最多的满足条件的区间的个数,我们不难想到用滑动窗口去做,即节省时间又高效,维护一个满足包含所有 m 种元素类型的区间,可以用双指针维护左右端点来记录区间,一开始左边界为L=1,右边界R暂定,循环遍历过程中同时记录包含的种类数ans,当ans=m的时候,更新一下区间数量sum+=(n-r+1),因为[1,r]满足那么r后面的每增加一个数构成的区间一定也满足。

AC代码

cpp 复制代码
int n,m,a[N];
unordered_map<int,int>mp;
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	int ans=0,sum=0,k=1;
	deque<int>q;
	for(int i=1;i<=n;i++)
	{
		if(mp[a[i]]==0)ans++;
		mp[a[i]]++;
		while(ans==m)
		{
			sum+=(n-i+1);
			mp[a[k]]--;
			if(mp[a[k]]==0)ans--;
			k++;
		}
	}
	cout<<sum;
}

J-凹包

题目来源

凸包的学习

在做这道题前,先了解下凸包
什么是凸包

简单说,给定平面上的点集,凸包是将最外层点连接成的凸多边形,能包裹所有点。

求凸包常用两种算法:Graham算法和Andrew算法,它们都得对点排序,时间复杂度都是O(nlogn) ,效率不错。这里咱们聚焦Andrew算法。

Andrew算法详解

  • 主要步骤
  1. 排序:先把所有点按x坐标为第一关键字、y坐标为第二关键字排序。排序后,第1个和最后1个点(第n个点)肯定在凸包上,这是后续操作的基础。
  2. 求下凸包:顺序枚举所有点,用栈维护当前在凸包上的点。新点入栈前,得判断栈顶的点要不要弹出。怎么判断呢?计算新点与栈顶两个点构成的有向直线的位置关系。要是新点处在由栈顶两点构成的有向直线的右侧或者共线,就把栈顶旧点弹出,直到不能弹了,新点再入栈。这一步是为了保证凸包的"凸性",把凹进去的点给过滤掉。
  3. 求上凸包:逆序枚举所有点,同样用栈维护。过程和求下凸包类似,也是通过判断点的位置关系,保证凸包的形状。要注意,每个点入栈最多两次,出栈也不超两次,总操作次数不超过4n ,效率有保障。
  • 代码展示
cpp 复制代码
struct Point{double x,y;} p[N],s[N]; // 定义点的结构体,p存所有点,s存凸包上的点
int n,top; // n是点的数量,top是栈顶指针

// 计算叉积,判断点的位置关系
double cross(Point a,Point b,Point c){ 
    return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
}

// 计算两点距离
double dis(Point a,Point b){ 
    return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}

// 比较函数,用于排序
bool cmp(Point a, Point b){ 
    return a.x != b.x ? a.x < b.x : a.y < b.y;
}

// Andrew算法主函数,返回凸包周长
double Andrew(){ 
    sort(p + 1, p + n + 1, cmp); // 排序
    // 求下凸包
    for(int i = 1; i <= n; i++){ 
        while(top > 1 && cross(s[top - 1], s[top], p[i]) <= 0) top--; 
        s[++top] = p[i]; 
    }
    int t = top; 
    // 求上凸包
    for(int i = n - 1; i >= 1; i--){ 
        while(top > t && cross(s[top - 1], s[top], p[i]) <= 0) top--; 
        s[++top] = p[i]; 
    }
    double res = 0; // 计算凸包周长
    for(int i = 1; i < top; i++) res += dis(s[i], s[i + 1]); 
    return res; 
}

下面回到本题。

解题思路

要判断一个给定顶点按逆时针顺序排列的多边形是否为凹多边形,核心思路是利用凸包相关知识。如果原始多边形是凸多边形,那么它的顶点应该和通过凸包算法得到的凸包顶点数量一致;如果是凹多边形,凸包顶点数量会少于原始多边形顶点数量 。因为凹多边形存在"凹进去"的顶点,这些顶点会被凸包算法排除掉,导致凸包顶点数变少。

AC代码

cpp 复制代码
pii a[N]; 
// 按 x 坐标升序排序, y 坐标升序排序
bool cmp(pii x,pii y){
    if(x.fi==y.fi) return x.se<y.se;
    return x.fi<y.fi;
}

// 计算向量叉积,用于判断三个点的转向关系
int cha(pii a,pii b,pii c){
    return (b.fi - a.fi) * (c.se - a.se) - (b.se - a.se) * (c.fi - a.fi);
}
pii tu[N]; 
int top=0; 
void slove(){
    int n;
    cin>>n; 
    for(int i=1;i<=n;i++)
        cin>>a[i].fi>>a[i].se; 
    if(n==3){ 
        cout<<"No";
        return ;
    }
    sort(a+1,a+1+n,cmp); 
    // 构建下凸包
    for(int i=1;i<=n;i++){ 
        // 当栈中至少有两个顶点,且新点导致最后两个顶点和新点构成的线段是"右转"或者共线时,弹出栈顶顶点
        while(top>1 && iaji(tu[top-1], tu[top], a[i]) < 0) { 
            top--;
        }
        tu[++top] = a[i]; 
    }
    // 记录下凸包构建完成后的栈顶位置,用于构建上凸包
    int t=top; 
    // 构建上凸包
    for(int i=n-1;i>=1;i--){
        while(top>t && cha(tu[top-1], tu[top], a[i]) < 0) { 
            top--;
        }
        tu[++top] = a[i]; 
    }
    // 如果凸包顶点数量小于原始多边形顶点数量,说明原始多边形有凹进去的点,是凹多边形
    if(top < n){ 
        cout<<"Yes";
    } else {
        cout<<"No"; 
    }
} 

F-迷宫穿越

题目来源

解题思路

用 BFS 找最短路径,同时处理 "消耗卷轴穿过障碍物" 的特殊规则。

需要记录 当前位置已用卷轴数量已花费时间 ,确保搜索过程中不重复访问相同状态。

从起点 (1,1) 出发,卷轴使用数 k=0 ,时间 dis=0。遍历上下左右四个方向。 遇到障碍物时,检查卷轴是否足够(k < K),足够则消耗卷轴进入。三维数组标记访问状态 v[tx][ty][tk],避免重复处理。到达终点 (N,M) 时,更新最短时间。

AC代码

cpp 复制代码
const int N=1006;
const int inf=1e18;
int n,m,K;
string mp[N];
struct node{
	int dis,x,y,k;
}; 
int d[4][4]={{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
void solve()
{
	cin>>n>>m>>K;
	string s;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		mp[i]="*"+s;
	}
	bool v[n+1][m+1][15]={false};
	int ans=inf;
	if(n==1&&m==1)ans=0;
	queue<node>q;
	q.push({0,1,1,0});
	v[1][1][0]=1;
	while(q.size())
	{
		node p=q.front();
		q.pop();
		int x=p.x,y=p.y,k=p.k,dis=p.dis;
		for(int i=0;i<4;i++)
		{
			int tx=x+d[i][0],ty=y+d[i][1];
			if(tx<1||ty<1||tx>n||ty>m)continue;
			int tk=(mp[tx][ty]=='#'?k+1:k);
			if(v[tx][ty][tk]||tk>K)continue;
			q.push({dis+1,tx,ty,tk});
			v[tx][ty][tk]=1;
			if(tx==n&&ty==m)ans=min(ans,dis+1);
		}
	}
	if(ans==inf)cout<<-1;
	else cout<<ans;
}
相关推荐
qq_5895681015 分钟前
javaweb开发笔记—— 前端工程化
java·前端
Zafir202431 分钟前
Qt实现TabWidget通过addTab函数添加的页,页内控件自适应窗口大小
开发语言·c++·qt·ui
阿巴~阿巴~33 分钟前
深入解析C++非类型模板参数
开发语言·c++
码农小灰37 分钟前
Kafka消息持久化机制全解析:存储原理与实战场景
java·分布式·kafka
多吃蔬菜!!!42 分钟前
vscode 搭建C/C++开发环境搭建(linux)
linux·c语言·c++
gihigo19981 小时前
matlab多目标优化差分进化算法
数据结构·算法
weixin_582470172 小时前
GS-IR:3D 高斯喷溅用于逆向渲染
人工智能·算法
程序员鱼皮2 小时前
太香了!我连夜给项目加上了这套 Java 监控系统
java·前端·程序员
Lin9成2 小时前
机器学习集成算法与K-means聚类
算法
JNU freshman2 小时前
算法 之 拓 扑 排 序
数据结构·算法