NOIP模拟29(B)
T1爬山
简单题,赛时找到了$O(1)$查询的规律于是切了。
从倍增LCA那里借鉴了一点东西:先将a、b抬到同一高度,然后再一起往上爬。所用的步数$×2$就是了。
抬升到同一高度的过程中,如果高度不是d的整数倍,则必定有一步没有走满d个高度。
如果剩下的步数为偶数,则直接累计答案,可以证明没有更优的情况(虽然我懒并没有证明但我觉得这挺显然的啊……)
如果剩下的步数为奇数,考虑把原来没有走满的那一步走满,然后把多余的那一步补到下降中,也可以证明没有更优的情况。(显然……于是我就又弃坑证明)
T2学数数
怕是考场上只有我一个人敲了一遍splay /捂脸.jpg
一开始以为是个平衡树果题,然后就写了。最需要处理的那一部分被我一个sb的sort给干掉了。
正解单调栈+离散化+桶。
开一个单调栈维护序列,栈内单调递减。
顺序扫序列的每一个元素。push的时候记一下push前栈顶元素,即为该点左侧第一个比它大的值。该点被pop的时候记录一下是哪一个元素pop了它,即为该点右侧第一个比它大的
值。(注意记录的都是位置)
算出左侧的长度l和右侧的长度r,$l×r$即为该点在最终序列里面出现的次数。
然后开桶统计前缀和,实现$O(1)$查询。
T3七十和十七
至今不知道dp转移方程的意义。。。
于是听了某一个打表找规律赛时A掉的大神讲了一下规律……
先鸽了,回头自己推一下或者稍微问一下……
NOIP模拟30(B)
T1Return
sb语文题,读了大概20分钟题。然而赛场上的代码各种错误于是完美爆零了。
正解sort+去重,累加答案的柿子题目都给出来了……
错误原因:
1.没注意输出格式冒号后面有一个空格
2.下面的东西显然不能处理出现0了的情况。
if(in_a[i]!=in_a[i-])
a[++n]=in_a[i],sum[n]=;
T2One
约瑟夫问题2改编题目。
结论:ans=(ans+i)%(n-i+1);
T3Magic
注意模数不一定是质数,crt就好
鸽了。
NOIP模拟31
T1math
赛时乱搞A了。把k和所有的ai取一个gcd,在k内递增,每个都取出来就好。
T2biology
赛时暴搜20分。
正解将坐标转化一下:(x,y)->(x+y,x-y),原本的曼哈顿距离($|x_1-x_2|+|y_1-y_2|$)转化为切比雪夫距离($max{|x_1-x_2|,|y_1-y_2|}$)。
然而我并没有严格按照正解打啊/滑稽.jpg
由于转移需要按照a的大小顺序,于是考虑将节点信息存进结构体里,按a的大小排序。
顺序扫一遍标记a变化的位置,按段转移。
由于需要加n个b数组,所以转移前加转移后加都一样。于是选择在转移后加。
用四个变量分别维护出$f[i]-x-y,f[i]-x+y,f[i]+x-y,f[i]+x+y$,然后进行状态转移:
$f[i]-x_1-y_1$用于转移$+x_2+y_2$,以此类推。
(其实直接把式子写开就是f[i]+(x_2-x_1)+(y_2-y_1),四种情况只是把绝对值拆了而已)
注意是按阶段转移的,所以需要8个变量,4个记录现在这个阶段以前所有阶段的max值,4个记录转移到当前节点的max值。
每个阶段末更新一下总体u最大值即可。
T3english
赛时暴搜20分。
20%算法:
暴搜。枚举左右端点直接暴力累加贡献。n<=1000测试点可过。
40%算法:
考虑另外20%数据的特殊性质:ai<=1。
对于ans1,不难发现,对答案有贡献当且仅当两个端点一个为0一个为1,此时对答案的贡献为1。于是答案就是(1的个数)×(0的个数)。
对于ans2,由于只有当区间内最大值为1时才对答案有贡献。而数列元素两两异或不可能大于1。故输出0即可。
100%算法:
不难猜测时间复杂度应该是$O(n)$或$O(nlogn)$。
考虑先用单调栈维护对于每个$a[i]$值左侧第一个比它大的元素的位置和右侧第一个比它大的元素的位置。
对于ans1,考虑对于每一位维护1的个数的前缀和,方便$O(1)$查询左右区间中1的个数。
考虑$xor$的运算法则,查询左边0的个数、右侧1的个数相乘然后左移对应的位数,左边1的个数、右边0的个数相乘左移对应的位数,求和然后乘上ai即可。
对于ans2,考虑用01trie解决问题。
1e6二进制下20位足够了,于是把每一个数字都按照20位从高位到低位插进01trie。
插入的时候别忘了记录一个num代表有多少个数插入的时候经过当前节点。
正解是可持久化01trie,但是我不会打又懒得学(我错了我去学)于是问了lockey大佬,
大佬说莫队优化可过。于是就用莫队过了……(记得自己yy一个删除操作)
查询的代码大概长这样:
inline void query(int k,bool lmt,int ri,int ai,int wei)//k为trie树上的节点编号
{//lmt为是否在下界,为1即前面几位都是恰好等于最大值的。ri表示对应ai的右区间中的数,ai即为ai,wei为当前查到第几位
if(!lmt)//如果!lmt,即下面的数字一定比ai要大,
{
ans2=(ans2+ai*num[k]%mod)%mod;//直接将维护的num累加进答案
return ;
}
int lin=(ri>>wei)&,pre=(ai>>wei)&;//取出两个值的这一位
if(trie[k][lin^])//如果lin^1的儿子存在,xor操作后为1,一定可以走。
query(trie[k][lin^],pre,ri,ai,wei-);//如果pre为0,走1一定大于ai了,所以没有限制。反之则依旧处于下界上
if(trie[k][lin]&&pre==)//pre为0才能走xor为0的节点,否则一定比它要小
query(trie[k][lin],lmt,ri,ai,wei-);//必定是下界
return ;
}
(我知道我写的跟shi一样但是我实在懒的写了就鸽掉吧回头找时间填坑反正也没有什么人看)