CF211 Div 1 题解

来源:互联网 发布:修改远程桌面端口 编辑:程序博客网 时间:2024/06/03 07:46




因为懒得再存着了,所以把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}


0 0
原创粉丝点击