CF211 Div 1 题解

CF211 Div 1 题解_第1张图片

CF211 Div 1 题解_第2张图片

CF211 Div 1 题解_第3张图片

CF211 Div 1 题解_第4张图片

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


你可能感兴趣的:(题解,codeforces)