HNOI 2019 简要题解

没想到自己竟也能有机会写下这篇题解呢。

LOJ Luogu

Day1T1 鱼

枚举\(AD\)两点后发现\(BC\)与\(EF\)相对独立,因此只需要计算合法的\(BC\)对数与\(EF\)对数,相乘即可。

先考虑计算\(EF\)的对数。确定\(AD\)后,满足条件的\(EF\)对数即为在某个半平面内与\(D\)点距离相等的点对数目。枚举\(D\)后若乱序枚举\(A\),则需要再\(O(n)\)地处理\(A\)确定的半平面内的合法点对数目。可以按照极角序枚举\(A\),并用单点指针确定半平面的范围,即可在总计\(O(n^2)\)的时间复杂度内解决这部分问题。

再考虑计算\(BC\)的对数。发现\(AD\)对\(BC\)的限制很强,直接限定了\(BC\)的斜率(或言之方向向量,因为有可能斜率不存在)以及中点坐标,因此可以考虑直接\(O(n^2)\)预处理出所有\(BC\)点对,每次查询时只需要在对应的值上二分找出范围限制即可。总时间复杂度\(O(n^2\log n)\)。

具体实现上,根据“与向量\((a,b)\)点积相同的点在一条垂直向量\((a,b)\)的直线上,与向量\((a,b)\)叉积相同的点在一条平行向量\((a,b)\)的直线上”,我们可以直接通过点积与叉积确定\(BC\)的具体位置。

code

Day2T2 JOJO

考虑解决没有\(2\)操作的子问题。

定义一个二元组\((x,c)\)表示有连续的\(x\)个\(c\)字符。考虑对一个由二元组组成的字符串求\(next\)数组。可以发现若\(next\)需要跨越某个二元组,则必须满足前后缀对应二元组相等(起始位置除外),这里的二元组相等定义为每一维均相等。起始位置二元组的字符要求相等而长度不要求相等,但必须大于等于前缀的对应位置。

现在考虑加入一个二元组\((x,c)\)后如何快速求得答案。沿\(next\)链往前跳时,每次遇到字符为\(c\)的二元组时,都能够为新加入的\((x,c)\)中的某一段区间找到其\(next\),其贡献为一个公差为\(1\)的等差数列。特别的,新加入的\((x,c)\)的一段后缀可能只能与首位二元组匹配,此时的贡献是首位二元组长度的若干倍。

这样就解决了没有\(2\)操作的子问题。当出现\(2\)操作时,常规的求解\(next\)数组的做法就不再适用了——求解\(next\)数组的时间复杂度是均摊的。因此,我们需要对求\(next\)的过程进行优化。首先离线建树,在自上而下\(dfs\)的过程中,维护每条\(next\)链上的\(kmp\)自动机(即\(f_{i,j,k}\)表示在\(i\)状态下加入一个二元组\((j,k)\)后\(next\)会指向哪里,同时即\(g_{i,j,k}\)表示对答案产生的贡献),每次修改是复制前一位的\(f\)数组,并将\(f_{i,x,c}\)修改为\(i\),将\(g_{i,x,1...c}\)修改为一个首项为前\(i-1\)个二元组总长度\(+1\),公差为\(1\)的等差数列,查询即查询前缀和。用可持久化线段树实现即可,复杂度\(O(n\log n)\)。

具体实现上,可以对\(g_{i,j,k}\)全体减下标,这样修改就变成了区间赋值。最后再加上下标的等差数列即可。

code

Day1T3 多边形

最优策略下每次旋转操作一定满足\(d=n\),因此总步数就等于初始局面下两端点均不是\(n\)的边的条数(边界上的边不计入)。

将初始局面下所有与\(n\)相邻的点(包括\(1\)和\(n-1\))排序,这样游戏终止的条件就变成了将。对于排序后相邻的两点\(l,r\),必然存在一条边\((l,r)\),否则原图就不是一个合法的三角剖分。此时若\(l+1=r\)那么这条边没有操作空间,可以直接忽视,否则在\((l,r)\)中必然存在一个点\(p\)使得\((l,p),(p,r)\)均有边,这样对\((l,r)\)进行一次旋转操作后即可得到边\((p,n)\),同时相等于在\((l,r)\)中间插入了一个数\(p\)。接下来区间\((l,p)\)与\((p,r)\)独立,方案数即可分别计算。

不难发现上述过程中隐含的树形结构。以初始局面下所有\(l+1<r\)的边\((l,r)\)作为树根,即可得到一片二叉树森林,其中每个节点必须在其父亲操作之后才能操作。这样方案数边不难计算:合并两棵子树的方案数为组合数。

对于一次任意的旋转操作,可以发现要么是在最优策略下操作了一步使得最优步数减\(1\),在树形结构上的表现为删除某棵二叉树的根,将其左右子树分别作为两棵新的二叉树,要么是对某个点(而且一定是左儿子)进行了一次\(rotate\)操作,不改变最优步数。两种情况的方案数均可以通过计算组合数逆元求出。

时间复杂度\(O(n+m)\)或\(O((n+m)\log n)\)。

code

Day2T1 校园旅行

有一个\(O(m^2)\)的暴力\(dp\)做法,记\(f_{i,j}\)表示是否存在一条从\(i\)到\(j\)的回文路径,转移即分别枚举\(i,j\)的相邻点转移即可。

这个\(dp\)可以进行一些小优化,额外记\(g_{i,j}\)表示\(i\)是否存在一个相邻点\(i'\)满足\(f_{i',j}=1\),这样转移就只需要枚举一遍,复杂度\(O(nm)\)。

(不知道怎么想的)考虑减少边数。对于所有连接同色点的边,每一个连通块内只需要保留一棵生成树即可得到与原图相同的结果。特别的,若该连通块不是二分图,则需要添加一条自环。对于所有连接异色点的边做同样的事情,这样总边数就降到了\(O(n)\)级别,再套用上面的做法即可。

code

Day2T2 白兔之舞

考虑枚举实际走了\(i\)步,会发现走\(i\)步的方案数恰好就是\(\binom Li\)。于是我们要求的答案就是:

\[b_t=\sum_{i=0}^L[i\%k=t]\binom Li(A^i)_{x,y}\]

随手单位根反演一下

\[b_t=\frac{1}{k}\sum_{i=0}^L\sum_{j=0}^{k-1}\omega_k^{j(i-t)}\binom Li(A^i)_{x,y}\\=\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{-jt}\sum_{i=0}^L\binom Li\omega_k^{ij}(A^i)_{x,y}\\=\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{-jt}((\omega_k^jA+I)^L)_{x,y}\]

令\(a_j=((\omega_k^jA+I)^L)_{x,y}\),然后原式(差不多)就变成了

\[b_t=\sum_{j=0}^{k-1}\omega_k^{jt}a_j\]

这不就是裸的\(FFT\)?

对于\(k=2^n\)的Case,直接\(FFT\)即可,复杂度\(O(3^3k\log L+k\log k)\),期望得分\(60\)分。

出考场后:

接着lun给我丢了份16年myy的集训队论文。

所以接下来我们做剩下的\(40\)分。

考虑\(jt=\frac{(j+t)^2-j^2-t^2}{2}\),于是原式就变成了

\[b_t=\sum_{j=0}^{k-1}\frac{\omega_k^{\frac{(j+t)^2}{2}}}{\omega_k^{\frac{j^2}{2}}\omega_k^{\frac{t^2}{2}}}a_j\]

移项后就可以直接卷积了!

然而此时你会发现\(\frac{x^2}{2}\)这东西有可能不是整数,也即需要用到\(2k\)次单位根,而和(du)善(liu)的lun一定也会造数据来卡你。

不过不要慌,转念一想,你会发现还有一种转化的方法:

\(jt=\binom{j+t}{2}-\binom j2-\binom t2\)

于是愉快地套用上式就行啦。

\[b_t=\sum_{j=0}^{k-1}\frac{\omega_k^{\binom{j+t}{2}}}{\omega_k^{\binom{j}{2}}\omega_k^{\binom{t}{2}}}a_j\]

\(MTT\)实现卷积即可,复杂度依旧为\(O(3^3k\log L+k\log k)\)。

code

Day2T3 序列

证明?看官方题解吧

第一个结论是答案的构造方式:从左到右依次加数,当发现当前的数比前边的数字小的时候就将整段替换成所有数的加权平均值,用一个单调栈即可维护。这同时也是\(50\)分\(O(nm)\)的做法。

以下所有下标(除了\(x\))均为单调栈的下标而非原序列的下标。

现在对\(x\)位置进行了权值的修改。考虑最终答案里\(x\)位置的所在区间(段),设之为\([L_0,R_0]\),则\([1...L_0-1],[R_0+1...n']\)在最终答案中的结构与单独考虑之的结构是一样的。也就是说只需要维护出所有前后缀的单调栈,再想办法对于每次询问找出\(L_0,R_0\)就行了。

考虑枚举一个\(R\)检查其是否可以作为\(R_0\),对这个\(R\)找出以其为右端点向左合并时会合并到的位置,记其为\(L\),则若\([L,R]\)的平均数小于\(R+1\)的权值则这个\(R\)就是我们要找的\(R_0\)。

枚举\(R\)可以改为用二分实现,同时对于一个给定的\(R\)我们可以通过在线段树上二分的方式做到\(O(\log n)\)地找到其对应的\(L\)。因此总复杂度\(O(n\log n+m\log^2n)\)。

code

HNOI2019 简要题解的更多相关文章

  1. BJOI2018简要题解

    BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...

  2. Noip 2014酱油记+简要题解

    好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...

  3. Tsinghua 2018 DSA PA2简要题解

    反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...

  4. Codeforces 863 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...

  5. HNOI2018简要题解

    HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...

  6. JXOI2018简要题解

    JXOI2018简要题解 T1 排序问题 题意 九条可怜是一个热爱思考的女孩子. 九条可怜最近正在研究各种排序的性质,她发现了一种很有趣的排序方法: Gobo sort ! Gobo sort 的算法 ...

  7. CQOI2018简要题解

    CQOI2018简要题解 D1T1 破解 D-H 协议 题意 Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法.它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信 ...

  8. AtCoder ExaWizards 2019 简要题解

    AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...

  9. Comet OJ - Contest #2 简要题解

    Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...

随机推荐

  1. 如何快速成为一名Linux运维工程师

    如今的互联网,绝大多数的网站.服务.游戏均是跑在Linux上面的,虽说Linux发行版众多,只要玩熟了一种发行版,了解了Linux精髓.基本架构.设计原理,其他都是触类旁通的,千万不要在选择哪一发行版 ...

  2. unity中鼠标按下加速漫游,鼠标抬起减速漫游。

    private bool IsMouseUpOrDown=true; //一开始默认是鼠标抬起状态 if (Input.GetMouseButtonDown(1)) //鼠标按下的瞬间状态 { IsM ...

  3. python之路 ---计算机硬件基础

    计算机(computer)俗称电脑,是现代一种用于高速计算的电子计算机器,可以进行数值计算,又可以进行逻辑计算,还具有存储记忆功能.是能够按照程序运行,自动.高速处理海量数据的现代化智能电子设备.一个 ...

  4. Java 算法(背包,队列和栈)

    Dijkstra的双栈算术表达式求值算法: import java.util.*; public class Main { public static double evaluate(String a ...

  5. SpringBoot 上传、下载(四)

    工程目录结构 完整代码: 1.pom.xml 首先当然是添加依赖,用到thymeleaf模板渲染html页面 <project xmlns="http://maven.apache.o ...

  6. 《Python》常用模块之collections模块

    内置的数据类型: int  float  complex str  list  tuple dict  set 基础数据类型: int  float  complex str  list  tuple ...

  7. :模板方法模式:Beverage

    #ifndef __COFFINEBEVERAGE_H__ #define __COFFINEBEVERAGE_H__ #include <iostream> using namespac ...

  8. 2.19 C++友元函数和友元类

    参考: http://www.weixueyuan.net/view/6350.html 总结: 借助friend关键字将其声明为友元函数,结果,在display函数体内,我们就能访问private属 ...

  9. SQL-5查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工

    输出描述: 题目描述 查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工CREATE TABLE `dept_emp` (`emp_ ...

  10. MicroBlaze核的串行接口实验:SPI UART

    reference : https://blog.csdn.net/weixin_42413559/article/details/80720566 串行接口:SPI UART XPS->SDK ...