佳木斯市第一中学NOIP真题模拟赛(19.8.24—19.8.25)游记

NOIP2013真题测试,先简单总结一下成绩。
Day1 180分
一般般的成绩,T1A掉,T2依靠玄学算法搞到了70分,T3的10分就很惨了,想到了LCA却没有继续往下想最大生成树,还是比较菜的
Day2 210分
Day2貌似来手感了
T1,T2A掉,T3还是只有可怜巴巴的10分,暴力广搜真的没有get到,打开一看就跑去写dfs了
总分 390分
个人认为还算可以,毕竟是一年的蒟蒻 ,看了下当年的分数线,发现并不是很高,然而tf告诉我现在考分数线最少300分……emmmmmm心里一凉。

Day 1

T1 转圈游戏

T1瞄一眼,10^9,搞毛啊,仔细一看居然是道快速幂水题,速度十分钟搞完,调试一下,出了几组数据搞一搞,就完事了
代码简洁,相信一看就明白了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m,k,x;
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=(ans*a)%n;
		a=(a*a)%n; b>>=1;
	}
	return ans;
}
int main()
{
	scanf("%lld%lld%lld%lld",&n,&m,&k,&x);
	int t=qpow(10,k);
	int res=(m*t)%n;
	printf("%lld",(x+res)%n);
	return 0;
}

其实没必要开long long ,考场上比较谨慎还是选择开了long long
T2 火柴排队

考场上的玄学方法,显然我们需要找两组数中相差最小的,每次对于第一组数a[i]中第i个数在第二组数b[i]中寻找与a[i]相差最小的数的位置,记为pos,每次移动时,需要将i到pos中所有的数位置向后移动一位,时间复杂度O(n^2),期望得分60pts,实际得分70pts

代码我忘记存了

满分算法:使a[i]中第k大的数与b[i]中第k大的数放在同一位置,即为最优答案

T3 货车运输

考场上想到了LCA,但发现是一个图就没再继续想,正解是最大生成树+LCA,最大生成树可以用并查集的Kruskal,将边权改为从大到小排序即可,LCA使用倍增LCA即可,在预处理倍增LCA时可预处理出minn[u][i],表示以u为起点,向上跳2^i次所经过最小的限重,在LCA时可以同时处理出路径上的最优解。

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define maxm 100005
#define maxn 100005
#define INF 0x3f3f3f3f 
int head[maxn],f[maxn],ff[maxn][25],deep[maxn],minn[maxn][25],vis[maxn];
int n,m,q,cnt=0;
struct node
{
	int x,y,val;
}ee[maxm];
struct Node
{
	int to,next,w;
}e[maxn*2];
inline int read()
{
	int w=1,s=0; char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch>='0' && ch<='9'){s=s*10+ch-'0'; ch=getchar();}
	return w*s;
}
int find(int x)
{
	if(x==f[x]) return x;
	return f[x]=find(f[x]);
}
bool cmp(node a,node b)
{
	return a.val>b.val;
}
void add(int x,int y,int v)
{
	cnt++;
	e[cnt].to=y;
	e[cnt].w=v;
	e[cnt].next=head[x];
	head[x]=cnt;
}
void kruskal()
{
	for(int i=1;i<=n;i++) f[i]=i;
	sort(ee+1,ee+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		int x=ee[i].x,y=ee[i].y,v=ee[i].val;
		int rx=find(x),ry=find(y);
		if(rx!=ry)
		{
			f[rx]=ry;
			add(x,y,v); add(y,x,v);
		}
	}
}
void dfs(int u)
{
	vis[u]=1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to,dis=e[i].w;
		if(vis[v]) continue;
		ff[v][0]=u; deep[v]=deep[u]+1; minn[v][0]=dis;
		dfs(v);
	}
}
int LCA(int x,int y)
{
	if(find(x)!=find(y)) return -1;
	int res=INF;
	if(deep[x]<deep[y]) swap(x,y);
	for(int i=22;i>=0;i--) 
	{
		if(deep[ff[x][i]]>=deep[y])
		{
			res=min(minn[x][i],res); x=ff[x][i];
		}
	}
	if(x==y) return res;
	for(int i=22;i>=0;i--)
	{
		if(ff[x][i]!=ff[y][i])
		{
			res=min(res,min(minn[x][i],minn[y][i]));
			x=ff[x][i]; y=ff[y][i];
		}
	}
	return min(res,min(minn[x][0],minn[y][0]));
}
int main()
{
	n=read(); m=read();
	for(int i=1;i<=m;i++)
	{
		ee[i].x=read(); ee[i].y=read(); ee[i].val=read();
	}
	kruskal();
	for(int i=1;i<=n;i++)
	{
		if(!vis[i]) {deep[i]=0; dfs(i); ff[i][0]=i; minn[i][0]=INF;}
	}
	for(int i=1;i<=22;i++)
	{
		for(int u=1;u<=n;u++)
		{
			ff[u][i]=ff[ff[u][i-1]][i-1];
			minn[u][i]=min(minn[ff[u][i-1]][i-1],minn[u][i-1]);
		}
	}
	q=read();
	while(q--)
	{
		int x=read(),y=read();
		printf("%d\n",LCA(x,y));
	}
	return 0;
}

Day 2

T1 积木大赛

考场上:这题我见过!
作为去年刚学两个月参加NOIP2018的我对第一题印象深刻,唯一得到70分的题,当时暴力找最长区间进行修改,时间复杂度O(n^2),期望得分:70分,实际得分:70分
正解:可以发现每次处理一个位置时,若此位置比前一位置小,那么此位置必定能被前一位置顺带处理,若此位置比前一位置大,那么在处理完前一位置后还需要加上剩余的次数,即(h-now)次(now 前一位置高度,h 当前高度),所以想法很简单了,从头到尾扫一遍,记录前一位置和当前位置,若当前位置大于前一位置,那么ans+=(h-now)

代码如下

#include <bits/stdc++.h>
using namespace std;
inline int read()
{
	int w=1,s=0; char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch>='0' && ch<='9'){s=s*10+ch-'0'; ch=getchar();}
	return w*s;
}
int main()
{
	int n;
	n=read();
	int ans=0,now=0;
	ans=read(); now=ans;
	for(int i=1;i<n;i++)
	{
		int h=read();
		if(now<h) ans+=h-now;
		now=h;
	}
	printf("%d",ans);
}	

T2 花匠

题目中说的十分复杂,但是我们画图理解后可以发现,人话题目就是从长度为n的数列中取出m个数,使任意除去首尾的其他数要么满足当前数大于左右两边的数,或者满足当前数小于左右两边的数,画图可以知道,这题就是让我们求波峰和波谷的个数,flag记录当前递增或是递减,发现当前数是波峰或波谷时ans++,并改变flag,为了最大化m,首尾数字必区,所以需要加2,当然我在循环中处理了最后的数字,所以只需要+1

代码如下

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
int h[maxn],n;
inline int read()
{
	int w=1,s=0; char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch>='0' && ch<='9'){s=s*10+ch-'0'; ch=getchar();}
	return w*s;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++) h[i]=read();
	bool flag=0;
	int ans=0;
	if(h[2]>=h[1]) con=1;
	for(int i=2;i<=n;i++)
	{
		if(flag==0 && i==n) {ans++; break;}
		if(flag==1 && h[i+1]<h[i]){ans++; flag=0; continue;}
		else if(flag==0 && h[i+1]>h[i]){ans++; flag=1; continue;}
	}
	printf("%d",ans+1);
}

T3 华容道

考试真是脑子抽了,dfs居然用来求最短路径
暴力分给的很足,然而我还是没拿到 ,广搜即可,因为挪动棋子可以变相看作挪动空格,所以每次广搜空格上、下、左、右的格子,广搜深度即最终答案,期望得分:70分

正解:广搜+最短路
这里的最短路推荐使用SPFA,比较好理解

spfa最短路 起点可能不在图中,再跑bfs连边。最后的目标状态就是指定棋子在tx,ty,然后枚举空格子在tx,ty的上下左右求最小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
牙科就诊管理系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线查看数据。管理员管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等功能。牙科就诊管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 管理员在后台主要管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等。 牙医列表页面,此页面提供给管理员的功能有:查看牙医、新增牙医、修改牙医、删除牙医等。公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。药品管理页面,此页面提供给管理员的功能有:新增药品,修改药品,删除药品。药品类型管理页面,此页面提供给管理员的功能有:新增药品类型,修改药品类型,删除药品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值