zoukankan      html  css  js  c++  java
  • 2019集训队作业做题实况[1](1-30):

    50-1(19.10.23)(树的性质):

    https://codeforces.com/contest/516/problem/D

    https://codeforces.com/contest/516/submission/63242051

    大意:
    给一棵树,定义(d[x]=max(dis(x,y)))

    求一个联通块(S),使得(max(d[x∈S])-min(d[y∈S])<=l),求(max(|S|))

    (d[x])肯定是(x)到直径两个端点的最大值。

    然后发现可以直接lct维护联通块大小。

    发现性质,若以d最小的为根建树,(d[fa[x]]<=d[x])

    那么就是扫描线,对于x,可以用树状数组直接统计子树里([d[y]<=d[x]+l]),因为连续。

    上网发现还可以直接用并查集维护联通块大小,删掉时直接减1,并查集不用变,还是因为连续。

    50-3(19.10.24)(计数+分治):

    https://atcoder.jp/contests/agc023/tasks/agc023_e

    https://atcoder.jp/contests/agc023/submissions/8106222

    大意:

    求满足p[i]<=a[i],p是一个排列,p的逆序对数和。

    考虑求p的方案数。

    从大到小给每个数选择位置,这样的话就可以确定这个数可以放的位置数。

    (cnt[i]=sum [a[j]>=i])(Ans=prod cnt[i]-(n-i))

    要考虑逆序对数的话,枚举两个(i,j(i<j)),假设(a[i]<=a[j])

    (p[j]>a[i])时,不会产生逆序对数,将(a[j])调整至(a[i]),发现恰好有一半的排列就是(p[i]>p[j])的。

    (a[i]>=a[j]),考虑用总数-顺序对数,顺序对数和上面一样,把(a[i])调整至(a[j])

    若调整(a[i]<=a[j]),则(cnt[x]--,x∈(a[i],a[j]]),对合法排列的影响可以预处理({cnt[i]-n+i-1over cnt[i]-n+i})的区间积来实现目的。

    这样得到了(O(n^2))的做法。

    用线段树分治来统计答案就是(O(n~log~n))的。

    50-2(19.10.24)(概率+积分):

    https://atcoder.jp/contests/agc032/tasks/agc032_f

    https://atcoder.jp/contests/agc032/submissions/8109887

    大意:
    一个圆被随机(n)条直径分割,设(s)为一个扇形的面积,求(min(|s-1/3|))

    第一步需要一个不可能想到的转换考虑把一条线定位0°,然后划分成三个区域,0-120°,120-240°,240°-360°

    这个区域里的划分看作三种颜色红绿蓝,然后全部(mod~120°)搞到(0-120°)里,发现问题变为(0-120°)里,随机(n-1)条划分,颜色也随机,求颜色不同的划分的最近距离,注意0°视作有一条红色的,120°视作有一条蓝色的。

    (n-1)条弧把1/3的区域划分成了(n)段。

    (E(i))表示长度为1的线段分成(n)段第(i)长段的期望长度。

    通过推理可以得到:

    $Ans=

    (Ans=sum_{i=1}^n 3^{i-1}*(E(i)-E(i-1))*{1over 3})

    即一条线段两个点同色的概率是({1 over 3}),要使(E(i)-E(i-1))被统计到,则(i)以前的线段都要同色,所以是(3^{i-1}),长度上限是({1over3}),还要乘({1over 3})

    问题在于求(E(i))

    先求(E(1)),设(P(i))表示长度为1的线段分成(n)段最短线段长度(>=i)的概率。

    (E(1)=int_{x=0}^{1/n} P(x) ~dx)

    (P(x)=(1-nx)^{n-1}),下面将解释这个东西:

    考虑把线段分为(a(a->∞))段,在其中随机选(n-1)个点就分成了(n)段,方案数是(a^{n-1})

    现在要求每一段线段的长度都(>=x),可以理解成少了(nx*a)个点,还剩(a-nx*a)个点,方案数是((a-anx)^{n-1})

    则概率就是((a-anx)^{n-1}/a^{n-1}=(1-nx)^{n-1})

    (int_{x=0}^{1/n} (1-nx)^{n-1}~dx)

    (=int_{x=0}^{1/n} x^{n-1} ~ dx)

    (=1/n^2)

    所以(E(1)={1 over n^2})

    然后推(E(2)-E(1))

    这个就比较简单了,(E(2))相当于还剩下(1-E(1)*n)的长度,分给(n-1)段,最短期望长度。

    那么就是(E(2)=(1-{E(1)*n})/(n-1)^2=n*(n-1))

    通过数归可以得到:(E(k)-E(k-1)={1over n*(n-k+1)})

    那么这题的答案就是:(Ans=sum_{i=1}^n {1 over 3^in(n-k+1)})

    49-1(19.10.26)(决策+贪心):

    https://codeforces.com/contest/506/problem/C

    https://codeforces.com/contest/506/submission/63412933

    https://codeforces.com/contest/506/submission/63421859

    大意:

    有n个竹子,第i个竹子长度为h[i],每天的结束会长高a[i]
    现在有m天,每一天可以做k次操作,每次操作可以选择一个竹子砍掉p,即高度h[i]=max(h[i]-p,0)
    你需要最小化m天结束后最高的竹子的高度
    n<=100000,m<=5000,k<=10

    首先二分答案x。

    solution1:

    然后发现直接顺着搞无法决策每次机会给谁。

    于是逆着搞,问题等价于,一开始每根竹子的高度是x,每次先降低a[i],操作可以拔高p,要求每根竹子任何时候高度非负,且最后的高度>=h[i]。

    那么这个问题十分简单,主要是没了max(0,h-p)这种不好考虑得东西,先把所有操作留着,当一个竹子要h<0时,就给他加p,最后再填到h[i],看操作够不够用就行了。

    要用(priority)_(queue)(set)被卡常。

    solution2:

    每根竹子至少要(c[i]=lceil {x + a[i]* m - h[i] over p} ceil),事实也不会要更多次。

    假设要多了一次,不如不做前面的那次不满p的,效果是一样的。

    然后设(d[i][j])表示第i根竹子的第j次操作至少要在(d[i][j])天后。

    (d[i][j])怎么求是个好问题。

    先思考(c[i])刀要满足什么才能合法,就是它们的效果和(>=x+a[i]*m-h[i])

    也就是(>=(c[i]-1)*p+(x+a[i]*m-h[i])~mod~p)

    则对于任意前(j)刀,砍的时候要满足:

    (h[i]+(d[i][j]-1)*a[i]>=(j-1)*p+(x-h[i])~mod~p)

    搞一下(d[i][j])就出来了。

    接着扫一遍,看看够不够用就好了。

    1-2(19.10.26)(性质+线段树):

    https://codeforces.com/contest/674/problem/G

    https://codeforces.com/contest/674/submission/63429991

    大意:
    给出n个数,每次可以对一个区间进行整体赋值,或者询问一个区间频率(>=p\%(20<=p<=100))的数。

    在编程之美上看过这样一个问题:
    有n个单词,其中有k个单词频率(>={1 over k +1}),其它的都小于({1over k +1}),要求利用(O(k))的空间找出这k个单词。

    考虑k=1的时候,只需要记录一个单词和一个计数器,如果新的单词和记录的一样,计数器+1,否则-1,当计数器=0时,记录的单词变为新的单词。

    (k>1),类似的,就记k个不同的单词和计数器,加入一个新的,有相同的就把计数器+1,否则计数器全部-1,有计数器=0的就替换。

    证明就是把上面的看做每次找k+1个不同的单词删掉,最后剩下的一定是那k个单词。

    对于这道题,可以看做做(k=lfloor100/p floor),用线段树维护,(O(k^2))暴力合并两个表即可。

    时间复杂度:(O(n~log~n~*k^2))

    49-2(19.10.31)(势能分析,线段树)

    https://codeforces.com/contest/679/problem/E

    https://codeforces.com/contest/679/submission/63884902

    大意:

    有一个序列,每次可以区间赋值,或者区间加,如果区间加完后这个区间有42的次幂,那就继续求,还有询问一个的值。

    42的次幂在int范围里的只有6个。

    我们对每一个数设一个(dis[i])表示(a[i])到下一个42的幂的距离。

    区间加法相当于dis区间减法,当减到<=0时,就顺便判一下并改一下,如果没有2操作的话,因为一个数最多被搞6次,复杂度就是:

    (O(n~log~n*6))

    考虑有了2操作,如果一个区间实际值一样,且dis<=0,那么一起修改,容易证明,复杂度还是:

    (O(n~log~n*6))

    48-1(19.10.31)(tarjan缩强联通分量)

    https://codeforces.com/contest/555/problem/E

    https://codeforces.com/contest/555/submission/63894938

    太水了不讲了。

    49-3(19.10.31)(转换模型+贪心+树形dp)

    https://atcoder.jp/contests/arc098/tasks/arc098_d

    https://atcoder.jp/contests/arc098/submissions/8223881

    大意:
    给出一个联通无向图,走到一个点的时候至少要有(a[i])的金币,可以花下(b[i])的金币买下这个点,求最少要多少金币才能把所有点买一遍。

    我只能想到先选(a[i]-b[i])大的比较优,但是这只能用于完全图的情况,然后就不会了。

    事实上可以这么转换问题,就变得明了。

    (c[i]=max(0,a[i]-b[i])),要保证只要在这个点上,(金币数>=c[i])

    这个问题,不难想到把(c[i])最大的提出来,越早买它越好。

    但是它的邻节点可以分成多个联通块,如果一开始就买了,可能就不能走到了其它地方了。

    所以一定留在最后一个联通块进去前买。

    (sumb[i])表示i为根的来联通块的(sum b)

    (g[i])表示i为根的联通块所需的金币数(-sumb[i])

    考虑(g[x])怎么转移,直接枚举最后走到的联通块y,因为(c[x])是子联通块里最大的,所以一定能不用额外的金币通过其它子树,对于这个联通块所需的额外金币是(max(g[y],c[y]-sumb[y])),取所有y的最小值即可。

    48-2(19.10.31)(辣鸡结论题):

    https://atcoder.jp/contests/agc032/tasks/agc032_e

    https://atcoder.jp/contests/agc032/submissions/8226893

    大意:

    把2n个数分成n对,使得(max((a[i]+a[j]) ~mod ~m))最小化。

    大胆猜想可以找到一个分界点,使得左边第一个和最后一个,第二个和倒数第二个……右边也是如此

    这样会最优,证明可以看题解那6个图,然后用不等式做做发现就是对的。

    题解:https://img.atcoder.jp/agc032/editorial.pdf

    于是二分这个分界点就好了。

    48-3(19.10.31)(博弈+最优化决策):

    https://atcoder.jp/contests/agc032

    https://atcoder.jp/contests/agc023/submissions/8229211

    大意:

    数轴上(n)个点,第i个点是(x[i]),人数为(p[i])

    一开始所有人在车上,车在(S)上,每次进行投票,往正或者往负走,到达一个(x[i])时,(x[i])上的(p[i])人会下来。

    每个人秃顶聪明,会希望自己在车上的时间最小,输出最后下的人的时间。

    *想题两小时,做题五分钟——论atcoder做题感受。

    很不自然地考虑(1)(n)两个地方的人的决策。

    (p[1]>=p[n]),即使(n)上面的人把车往右边拉,走到了(x[n-1]),由于(p[1]>=p[n]),车还是往回走。

    也就是(n)一定在(1)的后面,(T(n)=T(1)+x[n]-x[1]),所以(n)上面的人不如让(T(1))最小,也就是跟着(1)决策。

    (p[1]+=p[n]),现在变成了([1-n-1]),求(T(1))的子问题,递归求解。

    (p[1]<p[n])的情况同理。

    直到最后只剩一边的人,那么就不用决策了,直接走。

    43-1(19.10.31)(分段矩阵乘法):

    https://codeforces.com/contest/575/problem/A

    https://codeforces.com/contest/575/submission/63930223

    一眼题不说了,mdzz要判k=0和k=1。

    47-1(19.11.1)(矩阵乘法+倍增):

    https://codeforces.com/contest/576/problem/D

    https://codeforces.com/contest/576/submission/63987413

    (T(i))表示i时间,从1出发,能到那些点。

    (F(i))表示,(i)以前的边所形成的转移矩阵。

    (T(n+1)=T(n)*F(n))

    而这些边按时间排序,之间的(F)是一样的。

    用倍增去试即可,注意维护的是(F(n)^{1..x})的或和。

    47-2(19.11.1)(结论+二分图网络流):

    https://atcoder.jp/contests/agc029/tasks/agc029_f

    https://atcoder.jp/contests/agc029/submissions/8241674

    什么LJ猜结论题。

    我只能把题解复述一遍了。

    对于一棵树,当我们去掉一个点后,剩下的点和边必须有完美匹配,可以理解为以这个点作根,每个点和它到父亲的边匹配。

    对于每个点都要满足这个,这显然是有解必要条件。

    其实这还是充分条件。

    考虑分别以u、v作根,把两个完美匹配图取并集,你会发现一定有一条从u到v的路径,因为u、v的度数=1,而其他点的度数都=2。

    这也说明假设以(u)为根,跑完美匹配,如有(x,yin s[i],s[i]~choose~x)(x->y 连边)

    那么从u开始dfs,若满足之前的必要条件,一定能够走到其它的所有点(相当于沿着路径更改匹配的选择)。

    这恰好也是一组答案。

    10-1(19.11.2)(点分治二分树上凸函数):

    https://codeforces.com/contest/566/problem/C

    https://codeforces.com/contest/566/submission/64055933

    考虑一条链的情况,考虑选的位置是x,则代价=(sum abs(p[i]-x)^{1.5}*w[i])

    这是若干凸函数的和,还是一个凸函数。

    那么链上直接二分即可。

    树上用点分治二分即可,每次看往哪个子树走优。

    36-1(19.11.2)(库默尔定理+数位dp):

    https://codeforces.com/contest/582/problem/D

    https://codeforces.com/contest/582/submission/64057294

    很久以前做过的。

    https://blog.csdn.net/Cold_Chair/article/details/77488682

    9-2(19.11.2)(set):

    https://codeforces.com/contest/674/problem/D

    https://codeforces.com/contest/674/submission/64057984

    37-2(19.11.4)(动态规划):

    https://codeforces.com/contest/704/problem/B

    https://codeforces.com/contest/704/submission/64202127

    不错的一道拆绝对值dp题。

    x是递增的,那么我们不需要考虑具体是谁和谁匹配,只需要知道方向即可。

    从左往右做,左边就可以剩下两类点,一类是缺一条来自右边的入边,一类是缺向左的出边,一个点可以同时是第一类和第二类。

    (f[i][j][k])表示前i个点,一类点j个,二类点k个,最小值。

    然而在不考虑起点和终点时,(j=k),因为有入必有出。

    经过起点后,第二类比第一类多一个,经过终点后,第一类比第二类多一个。

    这样就少了一维。

    dp时可以记当前第二类比第一类多了h=0、-1、1个点。

    转移时注意除了一开始和最后,第一类和第二类点至少要有一个,不然就不联通了。

    4-3(19.11.4)(构造):

    https://atcoder.jp/contests/agc030/tasks/agc030_c

    https://atcoder.jp/contests/agc030/submissions/8291382

    发现竖着横着都不行,于是就斜着。

    使(n=k,color[i][j]=(i+j)\%n+1)

    你得到了和横着竖着一样的解法。

    发现这个东西,每一条斜线可以塞两个颜色……也不会错……

    2-3(19.11.4)(动态规划):

    https://atcoder.jp/contests/agc030/tasks/agc030_d

    https://atcoder.jp/contests/agc030/submissions/8292283

    考虑设(f[i][j])表示若干操作后,(a[i]>a[j])的方案数。

    若当前是交换(x,y)

    对f的影响就是,要么就是×2,即(i、j)(x、y)无关,要么就是很简单的转移。

    所以维护个整体×2标记,每次只修改相关的,最后统计一下就好了。

    13-2(19.11.5)(二元关系网络流):

    https://atcoder.jp/contests/agc038/tasks/agc038_f

    https://atcoder.jp/contests/agc038/submissions/8299844

    考虑每个环只有转一下和不转,我们可以对i讨论一下贡献。

    (1.p[i]=q[i]=i)

    不管怎样都不会有贡献。

    (2.p[i]=q[i],p[i]≠i)

    只有两个都不转或两个都转才没有贡献。

    (3.p[i]≠q[i],p[i]=i)

    只有q转了才有贡献。

    (4.p[i]≠q[i],q[i]=i)

    只有p转了才有贡献。

    (5.p[i]≠q[i],p[i]≠i且q[i]≠i)

    只有都不转才没有贡献。

    由第2条可以得到两边的方向是相反的。

    不妨设(p)属于(S)即选了,(q)属于(T)即选了。

    连边的话比较显然,不写了。

    4-2(19.11.5)(概率+生成函数|min-max容斥+dp):

    https://atcoder.jp/contests/agc038/tasks/agc038_e

    https://atcoder.jp/contests/agc038/submissions/8303241

    (P(i))表示i还没有结束的概率。

    (Ans=sum_{i>=0}P(i))

    直接算(P(i))并不好算。

    考虑设(Q(i))表示第i步已经结束的概率。

    (P(i)=1-Q(i))

    (Q(i)=sum_{d[j]>=b[j]且sum d[j]=i}{i! over d[j]!}*prod({a[j]over sum a})^{d[j]})

    写成EGF:
    (Q(x)=prod (e^{{a[j]over sum a}x}-sum_{k=0}^{b[j]-1}({a[j]over sum a})^k/k!*x^k)

    (P(x)=e^x-Q(x))

    暴力展开求出(P(x))

    考虑最后(P)的形式是:
    (sum c[i][j]*e^{{iover sum a}x}*x^j)

    忽略(c[i][j]),相当于求(e^{tx}*x^j)每一项系数和。

    (=sum_{i>=0}t^i*x^j/i!*(i+j)!)

    这个是EGF,所以乘上((i+j)!)

    (=j!sum_{i>=0}t^i*C_{i+j}^j)

    (=j!*({1over 1 - t})^{j+1})

    还可以min-max容斥+dp,只要有意识的靠,再推推式子就能出来,这里不讲了。

    31-1(19.11.6)(扫描线):

    https://codeforces.com/contest/538/problem/H

    https://codeforces.com/contest/538/submission/64347902

    这个题除了特别长以外就真的只是特别长了。

    先对每个联通块进行单独考虑。

    不是二分图直接无解。

    是二分图的话,对二分图的两边分别求区间交。

    现在问题就是看每一个二分图的两边分别分到那边。

    假设一个二分图的两个边的区间交分别为([l1,r1][l2,r2](l1<=l2))

    一共有三种情况:

    (l2,r2<=r1)

    (l2<=r1,r2>r1)

    (l2>r1)

    对这三种情况分别看(n1)属于每一个子区间时,(n2)能属于哪个区间。

    然后扫一遍,用个堆来维护即可。

    最后还要还原答案,想打出题人。

    29-1(19.11.6)(2-SAT):

    https://codeforces.com/contest/568/problem/C

    https://codeforces.com/contest/568/submission/64362913

    比较显然由字典序去填每一位。

    问题相当于有一些为已经确定,问是否有解。

    每个点拆位选'V'还是选'C',对一开始的边,正反都连一下。

    已经确定的点,可以直接dfs,或者连一条边继续判。

    注意要判只有'V'或者'C'的情况。

    22-2(19.11.6)(几何+简单线性规划):

    https://codeforces.com/contest/685/problem/C

    https://codeforces.com/contest/685/submission/64371840

    考虑二维的时候,我们把曼哈顿变成((x+y,x-y)),这样就变成了矩形。

    同样的,三维我们把它变成四维的:
    (a=x+y+z)

    (b=x-y-z)

    (c=-x+y-z)

    (d=x+y-z)

    二分答案ans后,求四维空间的交。

    当然并不是有交就有答案。

    若有(x,y,z)满足(a,b,c),它不一定满足(d)

    所以要限制一下(d),事实上(d=a+b+c),专门凑好的。

    那么这里做一个简单的线性规划可以解出(a,b,c)

    注意((x,y,z))要是整数,所以反解后得是整数。

    (x=(a+b)/2)

    (y=(a+c)/2)

    (z=(b+c)/2)

    可以得出((a,b,c))的奇偶性相同即可。

    解出最优答案的((a,b,c))后就好了。

    不知道为什么WA on 6,可能是解((a,b,c))时出了一点小问题,正负波动个2就能过了。

    30-2(19.11.7)(dp):

    https://codeforces.com/contest/704/problem/C

    https://codeforces.com/contest/704/submission/64453278

    每个点只出现两次,所以形成的图的每个联通子图要不是是环要不是链。

    直接dp,要判一堆(k=1)带来的猎奇情况。

    6-3(19.11.7)(mst):

    https://atcoder.jp/contests/arc093/tasks/arc093_c

    https://atcoder.jp/contests/arc093/submissions/8324595

    先做出个Mst。

    设mst的边权和为sum。

    (sum>X),显然(ans=0)

    (sum=X),设能在mst上的边有ca个,不在有cb个。

    考虑这ca个只要不全部同色就行了。

    (Ans=(2^{ca}-2)*2^{cb})

    (sum<X),设替换mst上的最大边后(sum>X)的有(cb)个,(sum=X)的有ca个。

    显然这ca个至少有一个和(sum<X)的异色。

    所以(Ans=2*(2^{ca}-1)*2^{cb})

    10-2(19.11.8)(SAM+dp):

    https://codeforces.com/contest/700/problem/E

    https://codeforces.com/contest/700/submission/64496361

    考虑把这个出现两次卡的紧一些。

    比如说一定有一次是后缀,这样答案并不会变。

    但是因为变成了后缀,所以可以在SAM上dp。

    考虑SAM上一个节点x代表着长度在一个区间的串,设(f[x])表示x代表的最长串的答案。

    (f[x])可以由(f[fa[x]])转移过来,至于为什么只考虑最长串之间的dp,可以看:

    https://blog.csdn.net/litble/article/details/81179442

    的证明。

    判断(f[x])能不能由(f[fa[x]])转移过来可以预处理(right)集的线段树。

    注意对每个x要多记(pos[x]),含义为:
    (pos[x]=y|y是x的祖先且f[x]=f[y]且min(dep[y]))

    每次实际转移不是(x)(fa[x]),而是(x)(pos[fa[x]])

    13-1(19.11.8)(构造+欧拉回路):

    https://codeforces.com/contest/528/problem/C

    https://codeforces.com/contest/528/submission/64499842

    胡乱构造题,自己造出来也不知道对不对。

    首先度数是奇数的点肯定要补成偶数的嘛。

    然后考虑对每个联通块,每个点都是偶数的度数,可以拉一条欧拉回路。

    如果欧拉回路的长度是偶数,那么只要正-反-正-反…就可以满足题目条件了。

    所以如果长度是奇数,随便在一个点那里加一个自环。

    19-1(19.11.8)(kruskal重构树+线段树):

    https://codeforces.com/contest/571/problem/D

    https://codeforces.com/contest/571/submission/64509298

    写完后看了别人的做法感觉自己弱爆了。

    当时一看这题,把类似Kruskal重构树的东西建出来,这样一个时间内的联通的点就在一个子树里了。

    然后通过线段树来打标记求出每个点最近被删的时间。

    再通过线段树区间加求和来搞定一个点在一个时间以前的答案。

    由于就是要做两遍几乎一样的东西,所以代码达到了200行,虽然写起来很快。

    23-1(19.11.8)(2-sat构造解):

    https://codeforces.com/contest/587/problem/D

    https://codeforces.com/contest/587/submission/64526348

    考虑每个边拆成选和不选。

    同一颜色的边在同一点可以得到限制。

    在同一点的边可以得到不能同时选的限制,这里新建一些前缀后缀的虚点来搞。

    然后二分答案,边权>ans的不能选,跑2-sat看有没有解。

    最后再随便给出一组解,这好像是我第一次写构造解。

    可以看这篇博客,有许多证明:
    https://blog.csdn.net/litble/article/details/80404751

  • 相关阅读:
    WEB API 系列(二) Filter的使用以及执行顺序
    C# 各个版本特征
    dapper使用
    windows设置自动清理log
    [Mime] MimeReader--读取Mime的帮助类 (转载)
    [Mime] MimeHeaders--MimeHeader帮助类 (转载)
    [Mime] MimeEntity--MimeEntity Mime实体帮助类 (转载)
    [Mime] MediaTypes--电子邮件类型类 (转载)
    [Json] C#ConvertJson|List转成Json|对象|集合|DataSet|DataTable|DataReader转成Json (转载)
    [功能帮助类] JsHelper--Javascript操作帮助类 (转载)
  • 原文地址:https://www.cnblogs.com/coldchair/p/11729416.html
Copyright © 2011-2022 走看看