417(8)DE - JoishBadeR - Holy Sh*t

417(8)DE

JoishBadeR posted @ 2014年4月18日 20:38 in CodeForces with tags CF , 4420 阅读

没参加比赛。。因为不是周末晚上家里没网。。。(很奇怪的性质对不对。。。

 

417 D 有N(<=100)个朋友,M(<=20)个题,每个朋友可以做一些题,但是你要邀请这个朋友必须要交xi元钱还有你家至少要有ki个物♂体,每个物♂体需要B元钱,问做完所有题需要多少钱。

是个N*2^M的状压dp,发现不能解决k的问题,那按照k排序,选了第一个那后面一定不用管了。

 

417 E 求一个N*M(<=100)的数表,使得每一行(列)的所有数的平方和加起来是个完全平方数

如果一行的数平方和加起来是个完全平方数,那把这一行的数都乘K也是一行合法的数,所以搞出一个1*N的向量和一个M*1的向量,乘起来显然是一组合法答案。构造向量的方法有很多,首先发现爆搜跑得飞快,还有一种构造方法就是

{N <= 2的时候特判;N = 2 * K, 构造1,1,..,1,K-1;N = 2 * K + 1, 构造1,1,...,1,2,K+1;}可以发现跟爆搜一样。。

 

418 D 一棵树(<=10^5)每次询问(<=10^5)两个点,每个点的最短路定义为到这两个点中短的那个,求所有点最短路中最大的那个。

据说是原题。。对于一个询问(u,v)可以沿其路径中点把树切成两部分,一部分到u最短,一部分到v最短,设到(u,v)lca长的那个是u,那么u那一部分的最远点就是一个点到u的距离+这个点子树中不走含u的路径中最远的那个,v那一部分也大概是这样,所以可树形dp,也可以维护个dfs序考虑没走一步对两边树上答案的贡献。有修改的话可以写树套树。

当然还有一种lct的在线做法,也可以支持修改,比这个要好写的多,这里不想再多说了。。

//叉姐太屌了。。提供了一种线性做法的思路。。这里我按照我的理解摆上

一种线性的在(离)线做法:对于询问(u,v),沿其中点切开,那么两棵树中到u(v)的最远点必然是两棵树的直径的两个端点的某一个。对于切割有这样一个性质:对于原树的一个直径,如果我们没有切开它,那么答案肯定是直径到询问点的距离。那么我们可以算出切点在直径上的2*Len棵树的直径,询问的时候分类讨论。

一种线性计算这2*Len棵树直径的方法:我们先把直径上的边全部断掉,形成了Len+1棵有根(根就是在直径上的点)树的森林,一字排开,用f[i]代表第i棵树到根的最远距离(即深度),用g[i]代表从左边开始前i棵树组成的大树的直径,t[i]代表从右边开始后i棵树组成的大树的直径,(这显然就是我们要求的2*Len棵树的直径)。

对于g[i],f[i]的意义变为从左边开始前i棵树组成的大树的且以i为根的最大深度

转移方程:g[i] = max(g[i-1],f[i]+f[i-1]+1),f[i] = max(f[i], f[i-1]+1)

大概是这样,如果不对自己yy一下就好了。。反正能线性。。。

于是我们求出来了要的东西。。现在只需要一个线性的在(离)线的lca就可以了,询问的时候如何判断切点是不是在直径上呢。又需要分类讨论了。。如果我们以直径的一个端点为根建一棵树,如果(u,v)的切点在直径上,首先他们的lca一定在直径上了。。之后就是距离的问题了。。首先线性预处理每个点到直径的距离是可以做到的。。然后就是一系列什么dist(u->Diameter), dist(u->lca), dist(v->Diameter)的判断。。总之很恶心就是了。。

要是不做到O(N)。。那我介绍这个东西也就没意义了!!总之很恶心。。。。以上。。。

 

418 E 题意是定义一个N(<=10^5)列无穷行的数表,第一行是固定的,之后第x行y列的数定义为:第x-1行第y列的数在第x-1行前y列中出现的次数。要求支持把第一行p(<=N)列的数修改为v(<=10^9),查询第x(<=10^5)行y(<=N)列的数两个操作。

打了个表找规律。。(?)发现有循环节,当然还有更简单的证明:

附一段聊天记录。。

//////

我给你举个例子。。。你就明白了



首先有些东西是纯循环的。。

有些是混循环的。。

我们先看纯循环的。。。

找个例子吧。。。比如说1 1 2 1 2 2 3

用ABCDEFG来表示

ABD
CEF
G

知道我在干什么吗?

不知道

ABD是那些1的位置

CEF是那些2的位置

一行一行排

变换一次之后

噢..明白了..

就变成竖着读

再来一次是横着读

所以显然是2……
 

至于为什么是混循环

就是因为可能一开始是
A
BCD

要先拍扁。。。变成
ACD
B
E

说实话。。。我感觉E反而可以用LCT维护。。
得到一个O(n log n)的方法。。
只要树状数组。。轻松带微笑
怎么树状数组。。
就是你看拍扁那个过程。。
你把竖着的每条链拿出来。。
如果你当前要竖着数。。
数到那一列是很容易维护的吧。。
关键是横着数。。数到哪一行
这个拿个树状数组。。
维护一些前缀和之类的。。
就能数到了。。
然后。。就能做了。
 
////
 
我们知道了除去第一行是有两个循环节的,假设询问第x列
询问偶数行第x列显然由定义可知就是第一行的a[x]在前面出现的次数,这个可以直接维护一个前缀和,num[i][j]表示数i在前j个里面出现的次数,这存不下。。那就分成T块,cnt[i][j]表示数i在前j块里的出现次数。。。然后就可以根号N求出这个数ans1了。。
那么奇数行的第x列要用上面求的偶数行的性质推出,啊。。大概是 在前面x列所有num[i][j]的值为ans1的数有几个。。这个也可以分块的、、但我嫌麻烦于是就开了T棵树状数组。。因为问题可以转化,转化成前面xxx块所有cnt[i][j]大于等于ans1的数有几个。。因为cnt不能明确表示某个位置的值,但是如果他大于等于ans1了。。那么这个块里一定存在一个位置使它等于ans1。。所以第i棵树状数组表示前i块的值小于等于j的cnt有多少个。。查询的时候就是 前xxx块里面大于等于ans1的值+后面一小部分与ans1相等的所有值。。但是这个值的个数不是O(N)的,因为一块里面最多根号N的数,所以只要考虑这根号N个数就可以了,
最后一个问题就是N根号NlogN的复杂度真的不会TLE吗。。
这个复杂度是一个伪上界。。而且CF太快了CF太快了CF太快了CF太快了。。。
问题解决了。。
ftiasch 说:
2014年4月21日 10:14

我的做法你可能说麻烦了,
如果可以O(1)在线LCA的话,可以很轻易地算出那条边,然后就很简单地线性了。

Avatar_small
JoishBadeR 说:
2014年4月21日 15:08

@ftiasch: O(N)-O(1)在线lca的方法不是xxx编号然后xxx吗。。(我只知道这个)这样写起来我感觉更恶心了啊。。(虽然说起来就更轻松了→_→


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee