7.1模拟赛赛后总结
赛时历程
二十分钟浏览题目,感觉今天的三道题应该都有能写的。
然后开始异想天开,打算在十点半之前拿下38+44+17=99分,然后再考虑后边能拿的。
结果T1暴力就写错了点东西,因为我忽略了到自己的dis这个事情,所以一开始是搞错了(然后并没有意识到,并发现找第K大就能过样例一,还在想是不是题面错了)。
然后打后边的十几分的换根DP,结果还整错了一会儿。结果打完T1并对拍完,(顺便发现暴力打错,怪不得那个K小好像得反过来算)就已经是十点多了。
本着能完成多少就多少的思想,我想着先搞定较简单的T3的17分。
还好,除了那个44分,十点半之前搞到了剩下的55分。
然后有点自闭,T2好像很难。这个时候我又困了。
来回看T2T3并懵逼到十一点半,清醒了不少,开始手画T2样例,画完样例感觉有点想法,于是从链做起,找链的结论的时候逐步完善判断状态是否合法的方法,于是十二点半的时候打完链,十二点四十五打完了前边的状压的分数。一开始计划的东西花了两倍時間才完成。
感觉这是最近打的最高的一次了,终于不是那三、五十分了,类目,于是剩下的時間仔细检查了一波(T2差点RE、分段要注意完全分割开,全局应用的一定要开成N)。
赛后发现
并列RK2,还好(比原来rk倒一好多了好吧/kk)。zyz又双叒叕 RK1了。冀队首归好像就会T1正解orz(虽然挂了。。
该拿的都拿到了。虽然因为这场比较简单吧。。去年他们那帮人好多AK的。。
技术总结
T1
想到什么权值线段树是理所当然,期望树高logn也是明明白白,但是并没有想到转化一下求dis的方式。树上求dis可以用 (dis(i,j)=dep[i]+dep[j]-2*dep[lca(i,j)]) 这样的方式,发现对于 (i) ,只需要找到第 (K) 小的(dep[j]-2*dep[lca(i,j)]) 即可,这棵树是随机的,所以说只要知道最多 (logn) 级父亲的线段树内存放的 (dep[j]-2*dep[x]) 即可,所以考虑从上到下dfs,假设现在线段树内有所有(x)的子树外的由父亲们fa产生的(dep[j]-2*dep[fa]),那么每次将(x)自己当lca加入自己子树内的所有 (dep[j]-2*dpe[x]) 到线段树内直接查找,暴力扫就行,因为这个树高导致复杂度是逐级递减的,就像点分治一样,然后进入儿子的子树之前要删除掉 (y) 内x做父亲的所有 (dep[j]-2*dep[x]) ,这样就保证了进入 (y) 的时候线段树内只有所有 (y) 的子树外的父亲们fa产生的(dep[j]-2*dep[fa]),出来的时候两个修改都删掉即可。
T2
先讲暴力,从链上可以知道,如果进行了(access(x)),那么会产生一个全1串,这个时候对这个串怎么添0呢?那就是在(1)~(x) 之间的任意一个点y进行(access(y)),这样y到儿子的边就会变成0,为了不重不漏的统计,考虑枚举每次第一个(access) 的点,然后在中间选择(access)来添0,不过不能对(fa[x]) 进行 (access),因为这样会到一个第一次就(access(fa[x])) 的局面,会算重。然后方案数量就是不access的方案(1) 加上access的所有状态(sumlimits_{i=0}^{n-2}sumlimits_{j=0}^{min(K-1,i)}dbinom{i}{j})。然后暴力的话就是把所有的边的状态状压一下,然后判断一下:
- 不存在一个点有两个实儿子。
- 达成这个状态需要的操作次数不超过K。
操作次数怎么算?发现要达成一个局面的最小操作状态是从下往上来的,而如果下边有一串1,那么每多一个0,就多一次操作次数,统计有1的边(最上边的那个,遇到1或者跳到根停止)往根走的0的个数即可。
然后是AC,精巧,简洁而就是不会。刚刚的暴力提示到操作要从下往上来,那么设计状态(dp[x][k]) 为 (x) 的子树下 (access) k次的状态数量, 然后考虑向上合并的时候,不同子树的状态肯定是乘法原理,但是只能有一个实儿子,所以说考虑是否 (access(x)),所以考虑一些辅助数组,设 (g[x][k]) 表示向上有实边的方案数,然后每次对于每个儿子进行转移时使用两个temp,一个是tempf,一个是tempg,每次考虑已经处理过的儿子 (f[x][j]、g[x][j]) 和当前的儿子 (f[y][k]、g[y][k]) ,更新的时候access的次数直接j,k相加,对于(tempf[x][j+k]),用 (f[x][j]*f[y][k]) 直接更新,对于 (tempg[x][j+k]) 它等于 (f[x][j]*g[y][k]+g[x][j]*f[y][k]) 表示选择当前y做实儿子或者选择已经遍历过的做实儿子,然后每次将temp复制到 (f[x],g[x]) 中,更新好已经遍历过的儿子,最后退出这层之前,要注意把 (g[x]) 复制到 (f[x]) 当中,因为刚刚考虑的都是儿子如何如何,向上考虑都是下一次DP决定的,刚才的遍历都只和儿子们的操作有关,然后对于 (f[x][0]) ,这个要归1,对于 (f[x][1]) 这个要-1,-1是因为对于 (x) 只操作一次多统计了一次 (access(x)) ,向上没有实边的话就不能有这个操作,那么最后实际上 (f) 和 (g) 差的只是 (f[x][1]) 和 (f[x][0]) .
T3
还是一个DP。考场上考虑到了每个配对是独立的,或许能够考虑计算答案为每个值的时候的方案数,但并没有朝着DP的方向想。设置状态 (f_c[i][j]) 表示某个配对 (c) 产生的绝对值为 (i) ,异或值为 (j) 的方案数,这个还是很好算的,只要枚举二者的取值即可计算出方案,然后将匹配结合起来的时候也可以通过类似的方式,最后统计的时候把方案*贡献累加即可,然后这个是可以在比大小的地方前缀和的,可以做到 (n^3) 。考虑换个状态,(f_c[i][j][0/1]) 表示某个配对 (c) 产生的绝对值为 (i) ,第k位异或值为 (0/1) 的方案,那么配对之间枚举每一位的取值然后算每一位的方案结合起来,比大小的地方也可以前缀和优化,而这个不用枚举异或可以做到 (O(n^2logn)) ,不错的复杂度。发现瓶颈在枚举初始状态的时候,计算(f_c[abs(i-j)][k][0/1]) 怎么更快呢?这个用多项式就好啦~(十级不考,战略放弃/kk)