因为懒得再存着了,所以把latex代码也贴上来
\documentclass[12pt]{article} \usepackage{amsmath} \usepackage{amsthm} \usepackage{amssymb} \usepackage{CJK} \usepackage{verbatim} \usepackage{indentfirst} \usepackage{syntonly} \usepackage{fancyhdr} \usepackage[CJKbookmarks=true, colorlinks, linkcolor=black, anchorcolor=black, citecolor=blackp, urlcolor=black]{hyperref} \usepackage{graphicx} \usepackage[top = 1.2in, bottom = 1.2in, left = 1.3in, right = 1.3in]{geometry} \usepackage{xcolor} \usepackage{paralist} \usepackage{ulem} %\usepackage{listings} %\usepackage{minted} \begin{document} \begin{CJK*}{UTF8}{gbsn} \hypersetup{CJKbookmarks = true} \pagestyle{fancy} %\lhead{\slshape\nouppercase{\leftmark}} %\rhead{} %\definecolor{bg}{RGB}{30, 30, 30} %\usemintedstyle{my} %\newminted[C++]{cpp}{mathescape, numbersep = 5pt, obeytabs, gobble = 10, frame = single, framesep = -2mm, bgcolor = bg} \title{\textbf{CF221 Div 1 题解}} \author{Kanari} \date{} \maketitle \setlength{\parindent}{2em} \setlength{\footskip}{30pt} \setlength{\baselineskip}{1.3\baselineskip} \let\enumerate\compactenum \let\endenumerate\endcompactenum \let\itemize\compactitem \let\enditemize\endcompactitem \setlength{\pltopsep}{5pt} %\setcounter{section}{-1} %\titlespacing*{\chapter}{0pt}{-50pt}{20pt} %\titleformat{\chapter}[display]{\normalfont\huge\bfseries}{\chaptertitlename\ \thechapter}{20pt}{\Huge} \newcommand{\graph}[2]{ {\noindent \begin{minipage}{\textwidth} \centering \includegraphics[width=#1]{#2} \label{fig:non:float} \end{minipage} } } \section*{前言} 虽然因为是小号而涨了rating,但这场考得实在太颓……尤其是D想了个TLE+MLE的算法,最后光荣FST。而且A和B都是开黑写的/抠鼻。 考的时候就隐隐约约觉得是中国人的题,考完一看,果然是中国人出的题。 \section*{A - Divisible by Seven} \subsection*{题意} 给定一个长度为$n$的数字,其中必定包含1、6、8、9。你可以把各位重新排序,判断能否排成某种顺序使得数字可以被7整除,并给出方案。 $n\leq10^6$。 \subsection*{分析} 关键就在于这个1689。事实上,1689可以排列出被7整除余$0\sim6$的数字。所以只要枚举1689的排列,然后判断即可。 \section*{B - Maximum Submatrix 2} \subsection*{题意} 给定一个$n\times m$的01矩阵,你可以任意改变行的顺序。求改变之后最大的全1矩阵的大小。 $n,m\leq5000$。 \subsection*{分析} 看到这数据范围就隐约觉得,这题肯定是中国人出的。我们考虑正常的求全1矩阵大小的$O(n^2)$方法,我们是枚举底边,求出每个位置能向上延伸的最大长度,然后单调队列扫。这里由于列的顺序是不变的,那么枚举矩阵的右边,求出向左延伸的长度。易得,最大矩阵一定是按这个长度排序之后的前若干行的矩阵。那么排序之后扫一遍。注意排序得基数排序,不然会TLE。 \section*{C - Circling Round Treasures} \subsection*{题意} $n\times m$的棋盘上,每个格子是空地或者障碍物。有些空地上有宝藏,有些空地上有炸弹。宝藏有一个可正可负的价值。给定你的起点,你每次可以走向一个四连通相邻的格子,并围出一个多边形。多边形内不能有炸弹,而你的收益就是多边形内宝藏的价值和$-$从起点出发要围出这个多边形的步数。求最大收益。 $n,m\leq20$,宝藏+炸弹数不超过8。 \subsection*{分析} 据说这是原题(BZOJ1294)。在此质疑一下出题人的心态。 首先,判断一个点是否在多边形内我们用射线法,即找一条不过多边形上点的射线,看与多边形交于几条边(这题还业界良心地告诉你了这个方法)。我们先对每个点找一条这样的射线。令$f[x][y][k]$代表,当前在$(x,y)$,集合$k$中的东西发出的射线穿过了多边形奇数次。$k$中可以包括宝藏也可以包括炸弹。那么转移时枚举下一步的格子,然后看有几个东西的射线会过这两个格子的连线。 想法还是挺神的,嗯。 \section*{D - Tree and Queries} \subsection*{题意} 给定一棵$n$个点的有根树,根为1。每个点有一个颜色。有$m$次询问,每次给定$x,y$,问在以$x$为根的子树中出现次数$\geq y$的颜色种数。 $n,m\leq100000$。 \subsection*{分析} 这题方法特别多,很好地体现了一题多解。 \subsubsection*{算法1} 先说一下我考场上想到的TLE+MLE方法。 考虑对颜色分块,分成重色(出现次数$\geq\sqrt{n}$)和轻\sout{友}色(出现次数$<\sqrt{n}$)。易得重色不超过$\sqrt{n}$种。我们需要预处理出以每个点$i$为根,出现次数为$k$($k<\sqrt{n}$)的颜色种数,记为$B[i][k]$,那么询问时只需要遍历所有重色就可以了。而对于重色,直接DFS求出现次数就行了。 考虑怎么预处理$B$。我讲下我考试的时候想到的$O(n\sqrt{n}\log n)$的方法。求出DFS序,枚举出现次数$k$,可以发现,实际上就是相当于问$n$个区间中出现了$k$次的颜色种数。而这是个经典问题,我们可以离线+树状数组解决。那么复杂度就成了$O(n\sqrt{n}\log n)$。于是光荣TLE。 在题解的讨论中有人讲到了$O(n\sqrt{n})$处理$B$的方法。我们枚举每种颜色,设这个颜色总共出现了$x$次。令$c_i$为以$i$为根的子树中当前颜色的出现次数,$f_i$为$i$的父亲。可以发现,$c_i$与$c_{f_i}$不同的点只有$O(x)$个。那么考虑一个这种颜色的节点,我们如果可以找到它的最近祖先$p$,满足$c_i\neq c_p$,那么只要把这条链的$B[c_i]$都加$+1$就好了。于是我们对$B$差分。而求这个最先可以用倍增,判断是否满足$c_i\neq c_p$时可以用树状数组维护DFS序查询。于是问题就在$O(n\sqrt{n}+n\log^2n)$的复杂度内解决了。不过由于内存卡的比较紧,在分块的大小上要多费些功夫。 这个算法应该是要提到的所有算法中最难写的一个。它唯一的好处大概就在于它是在线的,而其他算法都要离线。 \subsubsection*{算法2} 这·题·就·是·裸·的·莫·队。 求出DFS序之后直接莫队维护每种颜色出现的次数和答案。$O(n\sqrt{n})$,而且超好写。考试的时候就纳闷怎么这么多人20分钟随手秒…… \subsubsection*{算法3} 我们用一棵平衡树维护每棵子树中存在的的颜色以及对应的次数,用另一棵平衡树维护出现了$k$次的颜色种数。考虑合并两棵子树,我们枚举一棵中的所有颜色,然后插入另一棵,同时维护出现次数的信息。用启发式合并可以做到$O(n\log^2n)$。C++可以用\verb|set|,所以也很好写。题解中说有神一点的平衡树可以做到$O(n\log n)$,不明觉厉。 \subsubsection*{算法4} 题解的讨论中惊现沈洋大神,结合算法2和3给出了一个$O(n\log n)$的简单算法。我们还是用类似启发式合并(或者说是轻重链划分?)的思想,找出一个点最大的子树。我们直接用一个全局的数组维护每种颜色出现的次数和答案(就是莫队里用的那个),先递归处理所有小子树,处理完一个后从全局数组中删去小子树的信息。之后处理大子树,处理完后把所有小子树的信息加回来,再加上自己的信息,然后得到以自己为根的询问的答案。看上去是不是很不靠谱,但是用启发式合并的复杂度证明可以证明,每个节点只会被删去$O(\log n)$次。所以这货的复杂度就是$O(n\log n)$的。 \end{CJK*} \end{document}