2016 Multi-University Training Contest 4 solutions BY FZU
1001 Another Meaning
对于这个问题,显然可以进行DP:
令dp[i]表示到i结尾的字符串可以表示的不同含义数,那么考虑两种转移:
末尾不替换含义:dp[i - 1]
末尾替换含义:dp[i - |B|] (A.substr(i - |B| + 1,|B|) = B)
那么对于末尾替换含义的转移,需要快速判断\(B\)能不能和当前位置的后缀匹配,kmp或者hash判断即可。
复杂度:O(N)
1002 After a Sleepless Night
假设根已确定,可以发现新树若合法,需满足以下性质:根节点是n;儿子的值不大于父亲;具有相同值的节点形成一条链,并且链不会发生“分叉”(即有多个最低点)。所以对于新树中有出现的值x,原树在新树x链的最低点应为x,而其他新值为x的点,原值应小于x。那么我们先将所有链的最低点放上对应值,而空着的点和还没用的值进行配对。 贪心使答案字典序最小:从大到小枚举未用的值,用大根堆维护该值可以填入的位置id,取最大id填入。(否则,若某一步的值a匹配了非最大id x,而最大id y在后面配了值b,那么交换xy将产生更优解)。
还有一种方法是从大到小枚举空位置,填入 最接近小于 该位置新值的 未用的值。这用set是容易实现的。并且队友想出了使用并查集+双向链表的写法,可做到并查集复杂度(O(n*a(n)))。
不合法的情况除了不满足上述性质,还有就是匹配的过程中出现值或位置不够用。
然后考虑根的选择。由上所述,根的值一定是新树n链的两个端点之一。可以发现,无论选哪个做根,不影响其它链的上下方向及链之间的相对关系,即不影响合法性。因为没选的那一头一定填n,所以我们贪心地选择id小的端点做根(否则交换两个端点的值,将得到更优的答案)。当然也可以两个点都跑一遍。
(出题人写hint的时候,把自己绕晕了。不好意思。)
1003 Bouds
极小割边集的定义下割边集恰好会将原图分成两块。枚举左右两块是否独立连通。块连通必然可以删掉一个点,这个点与剩下的点有边且剩下的点连通,可以先状压每个点的边, DP转移即可。
接下来要处理的是将两个块之间的边加一。这部分可以处理成将左块中的边减一,右块中的边减一,整体加一。操作变成了把一个块的边加权值的操作。考虑一条边表达成形如 \(0..010..010..0\)的形式,它在所有块中的权值总和,便是求一遍把这个形式作为子集的集合的权值和,求一遍高维前缀和就可以了。
时间复杂度\(O(n\cdot 2^{n})\)
1004 Filling
对于一个覆盖情况只存在一种放置方式。
根据\(burnside\)引理,要统计顺时针旋转\(0^{\circ },90^{\circ },180^{\circ },270^{\circ}\) 下相同的方案数。
对于\(0^{\circ}\)的情况可以按照轮廓线DP,如下图.
对于\(180^{\circ}\)的情况先搜出中间几行的填放方式,奇数为三行,偶数为两行。这几行的最上可能会和上半部分冲突,上半部分同做一遍有初始值的轮廓线DP。
\(90^{\circ}\)和\(270^{\circ}\)是一样的。先搜出中心十字形宽度为两(偶数),三(奇数)的图形的方案。十字形的\(\ulcorner\)和右下部分产生冲突,按照下图的做一遍有初始值的轮廓线DP。
DP复杂度\(O(n^{2}\cdot 2^{n})\)
搜索范围比较小,且每次填放的格子数多,能在7~8秒内出解。
1005 Lucky7
因为满足任意一组pi和ai,即可使一个“幸运数”被“污染”,我们可以想到通过容斥来处理这个问题。当我们选定了一系列pi和ai后,题意转化为求[x,y]中被7整除余0,且被这一系列pi除余ai的数的个数,可以看成若干个同余方程联立成的一次同余方程组。然后我们就可以很自然而然的想到了中国剩余定理。需要注意的是,在处理中国剩余定理的过程中,可能会发生超出LongLong的情况,需要写个类似于快速幂的快速乘法来处理。
1006 Substring
处理出后缀数组中的sa[]数组和height[]数组。在不考虑包含字符X的情况下,不同子串的个数为\(\sum_{1}^{length} length-(sa[i]+height[i])\)
如果要求字符X,只需要记录距离sa[i]最近的字符X的位置(用nxt[sa[i]]表示)即可,个数为\(\sum_{1}^{length} length-max(nxt[sa[i]],sa[i]+height[i])\)
1007 Treasure
先求出树的dfs序,我们可以用点对表示一种可行方案,假设制定的路径起点为a终点为b,则可以用点对(dfs_id[a],dfs_id[b])表示路径。
假设钥匙在节点A,宝箱在节点B,\(C=LCA(A,B)\),则可以分四种情况讨论
1.\(C\neq A,C\neq B\)
对于这种情况,只要起点在以A为根的子树中,终点在以B为根的子树中,都可以拿到这份宝藏,而子树A中的所有节点dfs序连续,子树B同理,于是我们可以用一个矩阵表示能取得该宝藏的所有方案。
2.\(C=A,A\neq B\)
对于这种情况,需要先求出节点D,D为路径(A,B)上最靠近A的节点,那么只要终点在子树B上,起点不在子树D上的路径,都可以拿到这份宝藏,而不在子树D上的点,可以用一个或者两个dfs序区间表示,因此可以用最多两个矩阵表示能取得该宝藏的所有方案。
3.\(C=B,A\neq B\)
和情况2类似。
4.\(A=B\)
对于这种情况,若要求出所有经过节点A的路径,矩阵数目会是\(n^{2}\)级别的,因此反过来思考,求出所有不包含节点A的路径,对于全部这种情况来说这样矩阵数目的级别为\(n\)。可以对答案先累加宝藏权值,然后对于所有不经过该点的矩阵减去这部分权值即可。
这样我们就得到了一些带权矩阵,问题变成了在二维平面中,每次对一个矩阵内的所有点对加上一个权值,最后询问二维平面内点对的最大权值是多少,可以用扫描线+线段树解决,时间复杂度\(O(n\ log\ n)\)
1008 Turn Game
考虑能否在K步内得到染色方案S。
考虑每一行和每一列对最终染色的影响,可以贪心地得到每一行翻转小矩形(1x)没有交集。列上同理。考虑逐列加入,之前列如果某一行中有小矩形(1x),可以不花费地延续这个小矩形,如果没有则需要花费1的代价。行上的矩形考虑完毕后,列上的矩形的染色唯一,最小花费唯一。把状态\(F_{mask}\)设为表示每行小矩形是否延伸到当前列上所需要的最小花费。 转移方程为
\(F_{i,mask}=min(F_{i-1,cmask}+cost_{row}+cost_{col})\)。在考虑S是否可以在K步内得到,只要检查最终列里是否有一个\(F_{mask}\)是否小于等于K。整个过程做了一遍逐层的最短路。考虑这个转移中需要记录的信息是每列中的\(F_{mask}\),每列有\(2^{n}\)个花费。观察可以发现这些花费的最大值最小值之差不会超过n。把每层的花费同时扣除最小的那个状态的花费并将合并这些状态成为一个新的状态。这个状态的总数在n等于4时到达2000多个。
把这些状态直接连上边,边包含逐列加入的列的最终染色情况以及两个状态最小转移花费。在这些状态上做一遍DP,就可以得到最快能在K步内得到的方案数,累加一下就是答案。
总复杂度\(O(States\cdot 2^{3n}+States\cdot 2^{n}\cdot m \cdot K)\)
1009 String problem
网络流:最大权闭合子图。
思路如下:
首先将点分为3类
第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分)
第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费)
第三类:对于10种字符拆出10个点,每个点的权值为 -(b[x]-a[x])
那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字符s[i],那么就必须选中第三类中s[i] 对应的点,因为每个种类的点第一次选中时花费是b[s[i]],而第二类中花费都是a[s[i]],一定要补上b[s[i]]-a[s[i]],而且只需要补上一次。
得到上面的关系图后然后就是普通的最大权闭合子图问题,直接求解即可。
1010 The All-purpose Zero
0可以转化成任意整数,包括负数,显然求LIS时尽量把0都放进去必定是正确的。因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再算上0的数量。为了保证严格递增,我们可以将每个权值S[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的。
1011 Where Amazing Happens
1 写段代码处理一下题面。
2.人肉
1012 Bubble Sort
考虑一个位置上的数字c在冒泡排序过程的变化情况。c会被其后面比c小的数字各交换一次,之后c就会只向前移动。数组从右向左扫,树状数组维护一下得到每个值右边有多少个比其小的值,加上原位置得到最右位置,最左位置为初始位置和最终位置的最小值。
时间复杂度\(O(n\ lg\ n)\)