[图论][双联通分量][无向图仙人掌] UVALive 3514 Cactus

题意:求出给定图的生成子图里有多少个是仙人掌。

首先明确生成子图的概念:包括所有的顶点的子图(之前没有弄明白这个一直没有想出来),那么这个操作其实就很简单了,首先判断图形是否为仙人掌,如果是的话把其中所有的圈(其实在这里就是点双联通分量)所包含的的数量算出来,Π(cnt[i]+1)即为结果(每个圈最多只能去掉一个边)。

首先,判断是否为仙人掌,这个可以利用无向图仙人掌的性质在dfs求双联通分量的时候顺便求出来:对于任意一个dfs树上的节点u,他的反向边数量+他的子节点中low值小于pre[u]的数量<2,如果大于等于2说明这个节点附近已经产生了两个环了,不可能是仙人掌,反之如果所有点都满足这个要求,那么一定是仙人掌。

其次,求每一个圈的边数。这里如果是仙人掌的话,一定每个点双联通分量都是一个圈(否则就会被判定为非仙人掌,所以这里首先保证第一步的正确性是很重要的),这样的话只需要在求点双联通分量时在退栈的时候把每个bcc对应的边的数量记录下来就可以了(注意是边的数量而不是点的)。

最后套一个无聊的高精度板子就ok了,因为格式错误wa了几次。。。UVALive貌似经常有把格式错误当成wa的。。。顺便这个对高精度的要求还挺高,1000位都满足不了开了100000位才过,至于吗呵呵

继续阅读“[图论][双联通分量][无向图仙人掌] UVALive 3514 Cactus”

[CF][补题][递推计数][DP] codeforces 1043F Make It One

其实我用了一种操蛋的贪心试了一下,所有的cf测试数据里只有一组会错。。但是还没有搞明白为什么错了,也没有办法再继续证明正确性,所以还是放弃了去看tutorial,发现果然没思路就是dp。。。

然后这又不是一个正常的dp,甚至可以说不算是dp吧。。要从一堆数字里选出来一个集合使得gcd为1。确实,涉及到集合就很难操作。但是可以发现,如果这个集合存在,他的size是很小的,这里可以作为一个突破点去想。如果考虑枚举集合的大小,是否能有简单的计算方法。现在需要求的东西可以转化为,是否存在至少一个集合使得他的size为i然后gcd为1,当然这个也不好直接算,但如果再加一维,再枚举gcd,看看会不会有进展:这时候要求的转化为,是否存在至少一个集合,size为i,gcd为j。可以设一个dp[i][j]表示这种集合的数量,然后尝试是否可以递推。这时候可以发现这i个数字一定是从j的倍数里选出来的,所有的选法有C(cntj,i)种,其中cntj是原数列中j的倍数的数量。而这些里面又有一些不符合要求的,是因为他们的gcd=k*j,然后可以发现这些不符合要求的数量就是dp[i][k*j],这就实现了从大问题往小问题推的转移了。。。然后就只剩下边界的问题了,这个边界也很有意思:因为只考虑k*j<=max(ai)的gcd,所以大于的就是0就可以了

继续阅读“[CF][补题][递推计数][DP] codeforces 1043F Make It One”

[CF][尺取][减少重复计算] codeforces 1043D Mysterious Crime

emmm第一感觉好像后缀数组之类的结构,但是这个每个元素是个整数,而字符串处理中每个元素都是一个长度为1的字符,,,所以很难把他等同于字符串来处理。但是直接理解的话,要求的话一定是找到一个排列,然后考虑他的每个子段,然后再在其他所有的排列中去找有没有这个子段,直接裸暴力的话n^3*10,肯定不行,但是想一下如果仅仅是考虑所有的子段就一定是不小于n^2的了,所以起码要在这里进行优化。然后由字符串的性质就可以知道一个长度为i的串如果满足要求的话,那么他的所有子串也都是满足要求的这些子串可以不用再计算了,发现了这个之后怎么去实施这个想法?考虑以每个下标i为开始的最长子串,这里如果用暴力的方法每次从i开始递增, 然后在与其他串判断,则当然仍然是n^3的,但是可以发现与其他串判断这个过程其实有很多重复的判断,假如已经知道了i到i+k个存在的话,判断第i+k+1个时候只需要把这一个数字去和其他的串中对应的数字比较是否全部相等就可以了,这样的话把复杂度降到了n^2*10,但是仍然不够,再考虑之前说的,枚举字段中的重复假设已经知道以i开始的到i+k个数字满足要求,那么在算以i+1开始的子段的时候,可以直接从第i+1+k+1个数字开始,也就是说中间的那些都不用再考虑了,因为这些信息已经在算第i个的时候计算过了。所需要保存的只有每个序列中数字i出现的位置而已。

继续阅读“[CF][尺取][减少重复计算] codeforces 1043D Mysterious Crime”

[DP][转化目标] UVa 1289 Stacking Plates

附上一个讲的很好的链接https://blog.csdn.net/hao_zong_yin/article/details/79807322

第一感觉是类似矩阵连乘的那种操作,写完了才意识到复杂度会是2500^3,然后果断tle了(Final的题怎么会这么简单)。然后就没有什么太好的思路了。看了题解才有点明白。

这个题第一个难点在于,他又有分割又有合并,同时考虑这两种操作的话会很难设计状态转移,但是其实可以发现这两种操作的数量是有联系的,因为最初的堆数量是确定的,最后的堆数为1,所以分割和合并的数量关系可以确定出来,这样的话只需要算出来其中一种操作的数量就可以了,我这里考虑的是合并的次数w,经过推导可以得出最后答案ans与w的关系是 ans=2*w+n-1;(这个东西其实可以很简单的算出来:直接把每一摞盘子全到一起,总共的join次数为n-1,split次数为0;然后,每次在某一摞盘子内部进行一次split操作,则必然会在最后的结果中引入一次join操作,有一一对应的关系,因此可以推出来对于任意情况都有join次数==split次数+n-1)

第二个难点就是确定了要求合并的次数之后,如何进行dp。这里我们可以借鉴汉诺塔的思想,在考虑前i个(从小到大)盘子的时候,可以把大于i的盘子当成没有一样。而由于这里我关心的只是合并次数,所以不用考虑盘子的中间态(汉诺塔里盘子只能放在某个轴上,但是这里也可以放在地上),这样的话递推方程就会变得简单了。。。只需要使得dp[i][j]表示前i个盘子全放在第j堆上(想象一下这个画面)的最小操作数(这里要求第j堆必须有i这种盘子,说”这种”是因为离散化了),则转移的时候dp[i][j]一定是从dp[i-1][k]得来,其中1<=k<=n,而这时候又有不同的情况需要讨论 :①j==k,这时候如果有i的堆的数量为1,那么就是第j堆这个(因为我们规定只有j堆有i的时候才往这里转移),那么他就不需要动,直接dp[i][j]=dp[i-1][j];如果有i的堆的数量大于1,那就得先把j堆上的 (1到i-1) 这一坨移走,再把其他cnt[i]-1个i类盘子合并到j堆上,再把移走的 (1到i-1) 那一坨移回来(cnt[i]代表有多少堆含有i这个种类,可以预处理出来),所以总共增加的的操作数是cnt[i]-1+1=cnt[i],也就是这里的方程为dp[i][j]=min(dp[i-1][k]+cnt[i]);     ②  j!=k  ,这时候好说,只需要考虑第k堆有没有i就可以了,如果有那就多了cnt[i]-1次操作,如果没有就多了cnt[i]-1+1次操作(注意约定是j堆一定有一个才能往那儿转移,所以除了那一堆里的那个i,还剩下cnt[i]-1个i)。

其他的也就是离散化的操作需要谨慎一点,我由于写错这个wa了两发。。。去重的时候先保留能保留的再去重!不然有可能导致数组扫描完了却没有存任何一个数(比如整个数组都是同一个数)

 

更:今天起床看了看2个月之前做的这个题,觉得当时还是naive,每次直接考虑只向含有第i种盘子的摞转移就好了,于是重写了第二种代码(其实核心思想完全一样的)

继续阅读“[DP][转化目标] UVa 1289 Stacking Plates”

[DP][状压DP] UVa 1633 Dyslexic Gollum

自己想的时候一直在纠结的问题是怎么保存(第k个之前的是不是0/1)的问题,纠结了很久没有get到正点上,因为单单这样的话似乎会导致状态信息不足。。会漏掉一些情况。看了绿书题解,一看到状压顿时明白了。。。k最大只有10,这样的话只要把构造串的最后k位01情况压缩起来就可以了。另外一个问题就是这样的话会不会导致有中间产生长度超过k的回文串,答案是否定的,因为回文串本身其实有着子结构的性质,如果以某个节点为最后一位的长度k的回文串没有被构造出来,那么一定不会有更长的回文串包含这个点的。

继续阅读“[DP][状压DP] UVa 1633 Dyslexic Gollum”

[CF][DP][递推关系] codeforces 1068D Array Without Local Maximums

嗯。。。。果然还是那句话,直接上组合数学搞不定的组合数学,要么打表要么dp递推。

设dp[i][j][flag]表示前i数字,令最后一个数字为j时的方法数,其中flag==0表示第i-1个比第i个小,flag==1表示第i-1大于等于第i个,然后根据题目要求就是不能出现局部极大值,所以可以写出来递推式:① dp[i][j][0]=Σ(dp[i-1][k][0]+dp[i-1][k][1]) ,1<=k<j    ② dp[i][j][1]=dp[i-1][j][0]+Σdp[i-1][k][1],j<=k<=200 边界条件的话是单独考虑i==1的时候,特判算一下就可以了。这个方法是n*200个状态,每次转移再*200就是40000*n,太慢,观察到是求前缀/后缀和的形式,可以每一轮算完i之后维护一个presum[j][flag],保存这一轮的前缀和,这样的话可以O(1)转移,复杂度就变成了n*200 。

主要的思考的点就在于在满足题目条件的约束下递推,加了一维状态表示之后问题就变得很简单了,所以推不出来的时候可以考虑加维(增加dp的信息量)
由于偷懒到处取模所以代码很慢吧。。。不过dp重要的是思想hhh

继续阅读“[CF][DP][递推关系] codeforces 1068D Array Without Local Maximums”

[treeDp][状态分析][dfs] UVa12093 Protecting Zonk

这个题确实是,自己想没有整出来。由于多考虑了一层,状态变得复杂了。

首先还是转化为有根树去做,然后考虑下自底向上的推法。因为这里多考虑一层,所以还需要考虑子节点的放置情况,也就是除了考虑i节点放A/放B/不放,还需要考虑i的子节点,有没有放B/放A/不放,这样的话可以发现所有的情况到最后可以归类为4类,1)i处放B 2)i处放A且子节点放A/放B/没但是其字节点全放A/B,或者i处不放,其字节点至少有一个放B 3)i处不放,但是子节点全为2状态 4)能保证父节点放一个B就能覆盖到往下所有未覆盖路径的任意状态。然后就可以把状态转移方程搞出来,记忆化搜索即可。

自己思考存在的问题:脱离了无后效性这个基本点在想。如果按照一遍dfs来dp的思路,应该是保证了子树推出来之后才能推更高的祖先。

wa的话,因为用了一个cur的变量,之后再用却没有正确赋值。。。

继续阅读“[treeDp][状态分析][dfs] UVa12093 Protecting Zonk”

[数位+状压][DP] codeforces 1073E Segment Sum

这场前四个的难度跟后面的完全不是一个div的。。。abcd都很容易出的那种。。

然后今天这个E,怎么说,思路很容易想到,一看就是数位dp,然后也比较容易发现需要保存已经用过的数字集合,所以一个下标是状压的二进制。

然后我以为就这么开心的做了,但是操蛋的是,这个需要考虑很多前导0的情况。。然后我就写炸了。。。调了巨久。。。基本上后来就是各种特殊情况往上加,呵呵,虽然最后1y但是对我来说感觉做出来跟没做出来已经没什么区别了,浪费了n个小时(本来该看射频的啊啊啊啊啊啊啊啊凉凉

丑陋的各种特判代码先放这儿,等我去扒一扒前排大佬代码(其实cf那场也就不到100人A了这个题 继续阅读“[数位+状压][DP] codeforces 1073E Segment Sum”

[补题][贪心][数据结构优化][数学] Gym 101775B Scapegoat

首先可以确定要分一个trouble,那一定是等分,这一点可以从公式化简得到。

所以难的问题是,给每一个trouble分几个人。当没有什么做法/头绪的时候,想一想贪心递推的操作(贪心是因为这个题数据量不应该是dp),大问题是否可以从小问题转化过来,每次多一个人的时候,这个人应该放到哪儿?可以试着遍历每一个trouble看看放在哪里会使得变小最多,但是这样是M^2的做法,但是这时候考虑“哪里小的最多”这个条件,以及,+1之后哪里变小的最多是完全取决于trouble的数值和他当前已经有的人的,所以可以用一个优先队列来存储“哪里变小的最多”这个信息!这样的话就是M^logM的算法了,可以通过本题。

自己当时为什么想挫了?主要是一开始想的把一个划分之后可以看成两个新的数,但是事实并非如此,新分出来的和原来的是不等价的,同一个trouble分出来的可以互相组合,但是不同德trouble之间不能组合,所以这种思路可以否定。所以其实每次都要考虑所有的trouble,取变小最多的那个,想到这里又觉得是M^2的算法,又没有继续,但是这时候思路已经是对的了,就可以考虑可以用什么优化,尤其是这种最值/顺序之类的问题,可以多考虑数据结构优化。

继续阅读“[补题][贪心][数据结构优化][数学] Gym 101775B Scapegoat”

[逆向思维][差分][细节][补题] Gym-101775J Straight Master

自己思考的时候问题出在哪儿呢?还是没有挖掘和抓住问题的本质特征:要分成一段一段的,肯定是从一段一段的堆起来的过程过来的,如果能把这个过程还原,就可以判断出来是不是满足要求。一段的话,就有开头和结尾,然后开始找开头和结尾就可以了。自己的具有猜想性质的算法,如果不能及时证明,则应该换思路或者让队友去写样例试图证明,或者打样例表。

想出来差分之后,还有一个细节是如何判断3这个界限,其实有更简单的判断方法但是我这里写复杂了。但是整个题目重点还是在于逆向想到差分。

2019.7.10更新:今天翻到这个题发现自己以前写的是真诡异,写了个新的清爽版本。。。 继续阅读“[逆向思维][差分][细节][补题] Gym-101775J Straight Master”