【自用】每次NOIP模拟赛的总结 (无题面)

3 篇文章 0 订阅

我的最大缺点是思维混乱,特别是做数学题,变量的含义都搞混了
本来我设的x是 进行了x1次+a操作和x2次-b操作之后系数的和
然后有ax1+by1 =n ax2+by2 = m (每进行一次+a或-a,同时必须进行一次+b,-b,-b,+b,b取正负和a取正负是无关的,就像马走日 先走1步横再走两部竖)
然后我竟然认为x1 = y2…因为我想你走一个a同时也要走一个b
但这样的话x1就是净操作次数了,但x1是各种不同操作的总和啊,他不体现操作次数。。
就做错了orz
我应该把做法写出来,没错,把我做了什么都写在电脑上,用文字规范我的逻辑
我的逻辑:设x1为多次操作后实际走了的系数,那么把两个式子加起来,最后的解x3 = x1 + x2不一定有意义,因为他不一定满足走一次a走一次b
那么找找规律,什么样的解x3 y3满足题意,一定是走一次a走一次b的
发现x3 y3奇偶性相同才行
从0开始 a :+1 b:-1 发现总和a +1 b -1
然后a -1 b+1, 总和a 0 b 0
奇偶相同

然后发现我思维不严谨,T1的模拟打错了,看来想出来做法,一定要在符合题意下严谨地找反例,而且如果这种做法特别麻烦,说明很有可能找错了,我的缺点是有一个特别优美的算法,找了一个不合题意,不存在的反例,有时候又想出来一个特别麻烦的做法,没有找反例。
模拟题目大意
水会不断地往下下,有很多挡板,挡板有自己的高度,一块水能够存在,他左右下边必须都有水或挡板
这里写图片描述

是模拟先递减后递增吗??? 非也,反例很好找

这里写图片描述
而数据范围达到了10^6之大
要找到一种方法,直接扫一遍
那么换个角度做题,让我算一共多少块水,我不一定非要一大片一大片地算,我可以O(n)扫一遍,那么把这些水拆开,考虑每个挡板上方会有多少水,一个板上水的高度由他左右两边比他高的最小的两个板来决定

##找反例的方法 增加法 在优美地的两段中的一段加上一大段东西 或一点东西 看看会发生什么,比如这道题,一段递增一段递减 我再一段递增,想问题习惯由1推到2推到3至4到5 才能最大可能地保证不错

拼接字符串 321 32 谁在谁前面?
32321最好 但是321 字典序大于32 就很难受 不如把排序函数写成“对答案贡献大的可能情况 a排在b前面” return a + b > b +a
这样写cmp函数 可以理解为两两比较后一个个排好序,保留了对答案贡献最大的排列,那么这样新串字典序就是最大的

然后是T3
一棵树
给出两个节点,给出一条附加边,问附加边所连两点是否分别在以给定的两个节点的不同子树中
首先他题给我们一棵树,那么我们最好画的像树,不然会把树这种结构的性质忽略掉,就是说还是要画地特殊点,别画特别普适的情况,而且要把题意抽象出来,又不能乱来,搞得抽象地失去了这个题的“样子”,比如说我一开始把图仅仅是画成了n个点n-1条边的无向图而不是树,从而损失树的性质
考虑树上算法,dp,lca,dfs序差分,前缀和,树链剖分
那么判断两个点是否在不同子树中,其实可以看做两个点是否在不同dfs序区间中,dfs序非常有用,其实树链剖分就是应用了dfs序,可以吧树的问题转化为区间问题
###然而如何想到这些算法呢,这就有赖于总结了,先拿出所有学过的思想和算法,然后总结其能干什么,适用于哪类问题
但是我们也可以用lca来判断,就是慢和麻烦点
判断一个点是否为另一个点的子节点,直接用dfs序就可以,但是可以绕点弯路用lca 若x是y的祖先节点 则lca(x,y) = x
然后分情况讨论,因为附加边所连两点有可能是给定切断的两点的祖先
哎然后是思维题。。。讲真这种题我真不会做,唯一想到的就是由特殊推一般,正难则反等形式

###多刷基本算法题啊 什么贪心模拟单调队列单调栈位运算什么的

##ABC比赛。。。九月
注意dfs求组合数的时候若要在n个中选出m个
其实也可以看做保留n-m个 关键是m和n-m哪个更小
虽然最后底层节点数是相同的,但中间枝条数会不一样
更小的参数会更好

在debug的时候注意,若一个算法中有自己新搞出来的想法。。。那么很有可能这里是错的,比如说这个算法本来一贯是这么写的
然后因为题目限制你改了一下,那么改的这个地方就很容易出错。。。比如说我有一次写拓扑排序,本来先找所有入度为0的点入队,因为我建了新图,就直接遍历了所有的边,从里面找入度为0的。。。但是这样不对,因为可能把一个点多次入队,因为能有好多条起点相同的边,所以还要标记

模拟题能自己写二分就别lower_bound了,今天有个题让我找<=x中最大的一个我非得用lower_bound找>=x最小的那个。。。还有注意数组大小问题,搜索时用到的数组要贴合数据,不要超出去太多了,比如

bool check() {
	for(int i=1; i+m-1<=n; i++) {
		bool flg = false;
		memset(jud, 0, sizeof(jud));
		for(int j=i; j<=i+m-1; j++) {
			if(jud[a[j]]) {
				flg = true;
				break;
			}
			jud[a[j]] = 1;
		}
		if(!flg) return false;
	}
	return true;
}

因为有memset,所以可能会爆栈,而且注意jud的大小,因为jud是套了jud[a[j]]

一些函数或循环内部的变量定义时初置设为0真的挺好的。。。我今天打了个二分查找,当不存在比x更小的数时(全部大于x)按题意是返回0,但是我的二分里返回的是ans的初始值(因为ans一直没被更新),所以初始值设为0真的很重要

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值