Noip2018联训日记(Last update 11/9)

莫当繁星,皆挂苍穹

10月16日

subsets

map+vector枚举每个子集, O ( 2 n ) O(2^{n}) O(2n) O ( 2 2 n ) O(2^{2n}) O(22n),80分

折半枚举,左边 3 n / 2 3^{n/2} 3n/2枚举不选/第一组/第二组,然后计算第二组减第一组的差 x x x,map离散化 x x x y y y,将它们的的并存在 v e c t o r [ y ] vector[y] vector[y]中,后半段也如此 3 n / 2 3^{n/2} 3n/2枚举,与 v e c t o r [ m a p [ x ] ] vector[map[x]] vector[map[x]]中所有值取并,并打上标记,最后 2 n 2^n 2n检查标记,由于map里每个差最多来自 2 n / 2 2^{n/2} 2n/2对,复杂度最坏为 O ( 6 n / 2 ) O(6^{n/2}) O(6n/2)

swap

记忆化搜索, O ( n 3 ) O(n^{3}) O(n3),70分

有任意一个点的位置不变直接无解,否则就可以推断出一个数如何移动,以及在移动它的时候所需的方案的先后关系,若先后关系有矛盾也无解,不然问题就可以转化为一个大小为n-1的排列,某些地方限定了相邻两数的大小关系,求方案数,直接简单DP即可, f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个数,第 i i i个数在前 i i i个数中是第 j j j小的,前缀和优化, O ( n 2 ) O(n^{2}) O(n2)

moiezen

枚举 x x x再二分, O ( m i n ( n , p ) l o g ( n p ) ) O(min(n,p)log(np)) O(min(n,p)log(np)),50分

每次加上的 x x x一定是一个 p − a [ i ] p-a[i] pa[i]才最优,可以存下来然后去重,加上一个随机化,在枚举x的时候先去检查一下是否比目前的最优解要优,是才继续二分,由于一个随机排列中比前面所有数都大的数的数量期望为 l o g log log,所以复杂度为 O ( n p + n l o g ( n ) l o g ( p ) ) O(np+nlog(n)log(p)) O(np+nlog(n)log(p))


10月17日

dream

HK算法跑二分图匹配, O ( n 2 n ) O(n^{2}\sqrt{n}) O(n2n ),70分

将点从小到大排序,线段按左端点从小到大排序,维护一个可重集,枚举每个点,将左端点小于其的线段的右端点全部加入可重集,将比它小的右端点全部删掉,然后选取最近的右端点, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

toy

DFS,枚举每个球接在哪一个上面, O ( n ! ) ​ O(n!)​ O(n!),30分

DP, f [ i ] [ j ] f[i][j] f[i][j]表示一棵 i i i个结点的带标号树深度不超过 j j j的方案数, g [ i ] [ j ] g[i][j] g[i][j]表示一个 i i i个结点的带标号森林深度不超过 j j j的方案数

一个森林所有树的顶端连起来就是一棵新的树,并且深度增加1,即 f [ i ] [ j ] = g [ i − 1 ] [ j − 1 ] f[i][j]=g[i-1][j-1] f[i][j]=g[i1][j1]

一个森林加上一棵树还是一个森林,枚举最后面添加的树的大小k,注意到直接转移会造成重复,所以每次转移的时候要保证最小的点在新加入的树里面,即硬点一个点, g [ i ] [ j ] = ∑ k = 1 i g [ i − k ] [ j ] ∗ f [ k ] [ j ] ∗ C ( i − 1 , k − 1 ) g[i][j]=\sum_{k=1}^{i}g[i-k][j]*f[k][j]*C(i-1,k-1) g[i][j]=k=1ig[ik][j]f[k][j]C(i1,k1)

A n s = ( ∑ i = 1 n − 1 ( f [ n ] [ i ] − f [ n ] [ i − 1 ] ) ∗ i ) / ( n − 1 ) ! Ans=(\sum_{i=1}^{n-1}(f[n][i]-f[n][i-1])*i)/(n-1)! Ans=(i=1n1(f[n][i]f[n][i1])i)/(n1)! O ( n 2 ) O(n^2) O(n2)

icekingdom

每次询问扫一遍, O ( n 2 ) O(n^2) O(n2),50分

每次询问 [ l , r ] [l,r] [l,r]时,若其中一条边都没有,那么就会有 r − l + 1 r-l+1 rl+1个联通块,每当有一条边连接的两个点在 [ l , r ] [l,r] [l,r]之间,就会减少一个联通块,所以每次询问答案为 r − l + 1 − ( 俩端点在 [ l , r ] 之间的边的数量 ) r-l+1-(俩端点在[l,r]之间的边的数量) rl+1(俩端点在[l,r]之间的边的数量),可以离线下来用树状数组,也可以在线可持久化线段树, O ( q l o g ( n ) ) O(qlog(n)) O(qlog(n))


10月18日

cdq

CDQ分治, O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),36分

分别以 a b / a c / b c ab/ac/bc ab/ac/bc求三次二维偏序并全部加起来,这个可以随便做,对于每一对 ( i , j ) (i,j) (i,j),称 i i i大于 j j j i i i至少在两个维度上大于 j j j,比如( a [ i ] > a [ j ] a[i]>a[j] a[i]>a[j] b [ i ] > b [ j ] b[i]>b[j] b[i]>b[j] c [ i ] < c [ j ] c[i]<c[j] c[i]<c[j])或( a [ i ] > a [ j ] a[i]>a[j] a[i]>a[j] b [ i ] > b [ j ] b[i]>b[j] b[i]>b[j]且> c [ i ] > c [ j ] c[i]>c[j] c[i]>c[j]),前者在计算二维偏序时会被算一遍,后者在计算二维偏序时会被算三遍,且它们的和为 C ( n , 2 ) C(n,2) C(n,2),我们要计算后者的数量,所以 A n s = ( p x ( a , b ) + p x ( a , c ) + p x ( b , c ) − C ( n , 2 ) ) / 2 Ans=(px(a,b)+px(a,c)+px(b,c)-C(n,2))/2 Ans=(px(a,b)+px(a,c)+px(b,c)C(n,2))/2 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

来源

easy

暴力枚举选哪些数, O ( q 2 n ) O(q2^n) O(q2n),15分

先将 [ g , l ] [g,l] [g,l]里是 g g g的倍数又是 l l l的约数的数处理处理,不超过800个,最多8个质因数(后文一直假设有8个质因数)

选出的集合里的数必须满足每个质因数出现次数大于 g g g小于 l l l,且至少有一个顶上界/抵下界,所以状压DP, f [ i ] [ j ] f[i][j] f[i][j]表示选到第 i i i个,质因数顶上界的状态和抵下届的状态为 j ( 0 ≤ j < 2 16 ) j(0\leq j<2^{16}) j(0j<216)的方案数,枚举每个 i i i j j j以及是否选择这个数来转移

现在要硬点某个数 i i i必须选,可以正着一遍DP再反着DP ( f 2 [ i ] [ j ] ) (f2[i][j]) (f2[i][j]),计算不包含 i i i时的方案数,枚举 i i i前面的状态 j j j,其贡献为 ∑ k = 0 2 16 [ j   o r   k = 2 16 ] f [ i − 1 ] [ j ] ∗ f 2 [ i + 1 ] [ k ] \sum_{k=0}^{2^{16}}[j \ or \ k=2^{16}]f[i-1][j]*f2[i+1][k] k=0216[j or k=216]f[i1][j]f2[i+1][k],于是就可以可以 O ( 1 ) O(1) O(1)回答,总复杂度 O ( A c c e p t ) O(Accept) O(Accept)

来源or代码

hard

无输出, O ( 1 ) O(1) O(1),0分

不会,可参考官方题解


10月19日

错误整理


10月20日

自闭了,神仙题解

佬题是不可能改的,这辈子都不可能改的

bubble

枚举所有情况判断是否合法, O ( n ! ) O(n!) O(n!),0分

排列合法当且仅当最长下降子序列长度不超过2,然后不会了

brace

未找到源程序

不会

interval

未找到源程序

不会


10月21日-10月22日

摸鱼鱼


10月23日

set

发现了每个联通块要找俩互质的环,但是不会找,胡乱贪心, O ( ? ) O(?) O(?),5分

可以在每个每个联通块里选一个点BFS求它到其它所有点的最短路 C i C_i Ci,然后对于非BFS树上的边 ( i , j ) (i,j) (i,j),将其权值赋为 ∣ C i + 1 − C j ∣ |C_i+1-C_j| Ci+1Cj,然后求所有边权的GCD,若为 1 1 1,那么整个联通块里的点答案都为 1 1 1,在 ( i , j ) (i,j) (i,j)是反祖边时,其权值就是其所在环长度,否则就一定是一个环的长度减去另一个环的长度,用它来求GCD和用整个环长是等效的, O ( n ) O(n) O(n)

sequence

差分后马拉车, O ( n ) O(n) O(n),100分

rummikub

未找到源程序

记忆化搜索, f [ i ] f[i] f[i]表示没有抽到的牌集合为 i i i时的期望贡献,搜索时爆搜当前是否合法,合法直接统计剩下未抽的牌的权值和,不合法就枚举当前抽到哪一张继续往下搜, O ( 2 n n ) O(2^nn) O(2nn)


10月24日

gcd

根号枚举因数 i i i m i n ( n , m ) min(n,\sqrt m) min(n,m ),若 i ∣ m i|m im,就用 i i i m / i m/i m/i里较大的小于 n n n的值更新答案, O ( m ) O(\sqrt m) O(m ),100分

route

先在正图和反图上跑一边最短路并记录起点到每个点和每个点到终点的最短路,求出最短路DAG,询问时若一条边在最短路DAG上,就查询其是否是支配边,是就 p u t s ( " 1 " ) puts("1") puts("1"),否则 p u t s ( " 0 " ) puts("0") puts("0"),不在最短路DAG上的边 i i i可以直接查询 ( d i s 1 [ t ] + d i s 2 [ s ] + l e n [ i ] ) (dis1[t]+dis2[s]+len[i]) (dis1[t]+dis2[s]+len[i])是否比最短路小,是就 p u t s ( " − 1 " ) puts("-1") puts("1"),否则 p u t s ( " 0 " ) puts("0") puts("0") O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)),100分

最短路和最短路DAG很好搞,支配边不好做,下面是一些做法

  • 支配树:不会
  • 树链剖分:还行,复杂度较高
  • 流量1:给点 1 1 1赋一个流量 1.0 1.0 1.0,从其每条边连出的边的流量为 1.0 / d e g [ 1 ] 1.0/deg[1] 1.0/deg[1],其它点进入的流量为其入边流量之和,对其出边也这样做,一条边是支配边当且仅当其流量恰好为 1.0 1.0 1.0
  • 流量2:上面那个方法可能会爆精度,可以将浮点数改为模意义下的值,也可以不一定均分流量,可以随机赋流量,只要每个点流量平衡就行了

seq

胡乱贪心, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)),0分

先将相同的一堆数缩成一个( n n n会变小),然后离散化,可以知道此时最终形态,先假设最终形态里两两全部需要割一次,就是 n − 1 n-1 n1次,然后考虑只有数字增加 1 1 1的地方才可能使答案减小 1 1 1,可以统计原序列有多少相邻的对,但是若有长度在 2 2 2个及以上的连续相邻对,且中间的数字出现超过 1 1 1次,就不得不考虑这个分配给前面还是后面。胡乱写的(错误的)贪心,每次遇到决策优先分给前面,如果后面有重复就再重新分配,可能会出现重复决策,于是挂掉了。正确的是按离散化后权值类DP扫一遍,每次选择后后面那个位置一定不能再选,于是维护俩pair<贡献,被ban掉的位置>最大值和次大值,最后选最大值即可, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))


10月25日

tree

倍增出祖先和链上最大值,然后预处理另一棵倍增树表示一个往上跳的倍增序列, O ( q l o g ( n ) ) O(qlog(n)) O(qlog(n)),100分

circle

未找到源程序

不难发现最短路径必定是三元环,于是就是要统计有多少三元环,对于一个三元环 ( i , j , k ) (i,j,k) (i,j,k),其不合法当且仅当某个点连出去两条边,于是可以考虑用总数减去不合法三元环数量,每个不合法的三元环只会被一个点连出去两条边的时候被统计,于是只需要知道每个点的已确定出度 a a a和未定义的边数 b b b,其不合法的期望为 a ∗ ( a − 1 ) 2 + a ∗ b 2 + b ∗ ( b − 1 ) 8 \frac{a*(a-1)}{2}+\frac{a*b}{2}+\frac{b*(b-1)}{8} 2a(a1)+2ab+8b(b1) O ( n ) O(n) O(n)

gift

部分分, O ( n 2 ) O(n^2) O(n2)| O ( 值 域 2 ) O(值域^2) O(2)| O ( 400 0 2 + 50000 ∗ 500 ) O(4000^2+50000*500) O(40002+50000500)| O ( 400 0 2 + ? ) O(4000^2+?) O(40002+?),50分

第一个是裸的,第二个可以转为点然后在坐标系上DP,第三个可以发现坐标大于 4000 4000 4000的点顶天 500 500 500个,可以把这些点提出来,剩下的点按第二部分分做,然后枚举这些点,暴力和其它点算答案,第四个和第三个没什么区别,在随机数据下可以过掉(千万不要加一次答案取一次模,应该开个 l o n g   l o n g long \ long long long最后取模,速度会快很多)

但是很明显会有一些毒瘤会来卡第四个,它们会出 4000 + 4000+ 4000+个坐标大于 4000 4000 4000的的点,剩下的用较小的点填充,然后复杂度会炸,不过有大佬指出如果把较小的那些点去重统一算答案复杂度似乎可以对,据说是不足 O ( 1.4 e 8 ) O(1.4e8) O(1.4e8),不过我也不清楚,反正可以过, O ( A c c e p t ) O(Accept) O(Accept)


10月26日

contemplation

2 i 2^i 2i的权值意味着我们必须不惜一切代价选当前编号最大的点,若实在太远不能选,就一直往下直到可选,贪心选 n − k n-k nk个,将 n n n设为根节点,每次选择一条链,所以可以倍增找到最近已选择祖父, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)),100分

lost

切比雪夫距离转化为曼哈顿距离,然后枚举每个点为终点,二分查找计算绝对值之和, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)),100分

apporach

每个联通块从一个点开始BFS,设其权值为 x x x,那其它点可以用 a x + ax+ ax+b来表示,由于每个点都有上限,所以可以维护出最小/大值,如果某个点访问过,就判断是否合法,此时x的大小也唯一确定了, O ( n ) O(n) O(n),100分


10月27日

physics

倍增迭代, O ( 15 q ) O(15q) O(15q),100分

等比数列求和更快, O ( q ) ​ O(q)​ O(q)

math

Lucas定理, O ( q l o g ( n ) ) O(qlog(n)) O(qlog(n)),100分

不难看出可将 [ 1 , n ] [1,n] [1,n]划分成以每个奇数 i i i开头的集合 { i , 2 i , 4 i , . . . } \{ i,2i,4i,... \} {i,2i,4i,...},每个集合互不影响,而且在集合内部必须是在奇数位上的数放在一块,偶数位的放另一块,对于偶数大小的集合,其能贡献 2 2 2 s i z e / 2 size/2 size/2的方法,对于奇数大小的集合,其能贡献 s i z e / 2 size/2 size/2 s i z e / 2 + 1 size/2+1 size/2+1的方法(可以看作必定贡献 s i z e / 2 size/2 size/2后可以选择要不要再贡献 1 1 1),在找出所有集合后,可以减去不论怎么选都必须存在的大小,方案数即为 C ( 奇数集合数量 , x − m u s t c h o o s e ) ∗ 2 偶数集合数量 C(奇数集合数量,x-must_choose)*2^{偶数集合数量} C(奇数集合数量,xmustchoose)2偶数集合数量 O ( q l o g ( n ) ) O(qlog(n)) O(qlog(n))

geography

暴力|并查集, O ( n m ) O(nm) O(nm)| O ( m ) O(m) O(m),50分

离线后线段树和带撤销并查集分治, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))


10月28日

摸鱼鱼


10月29日

string

每次询问将整个 [ l , r ] [l,r] [l,r]扫一遍,贪心得到答案, O ( n 2 ) O(n^2) O(n2),50分

线段树,每个结点维护 f [ 0 / 1 ] [ 0 / 1 ] f[0/1][0/1] f[0/1][0/1]表示左边要进位/不进位和右边需要进位/不需要进位时该区间变为 0 0 0的答案,显然在叶子结点时,若该位为 1 1 1,则 f [ 0 ] [ 0 ] = 1 , f [ 0 ] [ 1 ] = 1 , f [ 1 ] [ 0 ] = 1 , f [ 1 ] [ 1 ] = 0 f[0][0]=1,f[0][1]=1,f[1][0]=1,f[1][1]=0 f[0][0]=1,f[0][1]=1,f[1][0]=1,f[1][1]=0,为 0 0 0时, f [ 0 ] [ 0 ] = 0 , f [ 0 ] [ 1 ] = 1 , f [ 1 ] [ 0 ] = 1 , f [ 1 ] [ 1 ] = 1 f[0][0]=0,f[0][1]=1,f[1][0]=1,f[1][1]=1 f[0][0]=0,f[0][1]=1,f[1][0]=1,f[1][1]=1,往上更新时枚举 16 16 16种情况分别更新, O ( q l o g ( n ) ) O(qlog(n)) O(qlog(n))

safpar

裸dp, O ( n 2 ) O(n^2) O(n2)| O ( 500 n ) O(500n) O(500n),40分

最大值分治,可以搜下去也可以单调栈预处理完后扫一遍,使用差分优化, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

walk

未找到源程序

不会


10月30日

今天变懒了,都没有自己写解析

algebra

DFS爆搜, O ( n 8 ) O(n^8) O(n8),30分

先利用逆序对判断是否有解,详见滑块游戏有没有解,有解的话就按照下文的方法搞, O ( n 3 ) O(n^3) O(n3)

首先通过移动空白方块填充好右侧n−2列和下方n−2行组成的矩形区域,然后每次填充一个1×2或2×1的空间。具体地,对于填充最右侧2×1的空间,先将右下角的数移动至右上角,再将右上角的数移动至这个数左侧,然后就可以填充好了。注意判断特殊情况,或者使用搜索找寻路线避免移动已经移好的方块。

decoration

瞎状压DP, O ( 2 n n ) O(2^n n) O(2nn),65分

真状压DP,见下文, O ( 2 n n 2 ) O(2^nn^2) O(2nn2)

考虑将树上每个点的状态依次写成一个01序列,那么拨动一个点的开关的动作可以看成把这个序列异或该点及其所有祖先位置为1的01序列。注意这个转化也处理了拨动效果互相抵消的问题。由于可能在中途达成目标状态,所以按时间从晚到早进行状压dp,第i次选择在倒数第i秒被拨动的点,那么它距离少于i的祖先会被影响,可以预处理出这个影响进行转移。f[i][j]表示当前在倒数第i秒,01序列j为当前树上点的状态。转移时枚举这一秒拨动的开关(或者不操作)。

lunch

未找到源文件

先把 − 1 -1 1 h i h_i hi设为 i n f inf inf,而且它们不能变小,对于每条边 ( x , y ) (x,y) (x,y) R i ≤ h x R_i \leq h_x Rihx那么为了满足 h x h_x hx不在这条边被更新,就必须有 h y > L i h_y>L_i hy>Li,而且它们在 L i L_i Li处吃饭才行,那么就把 h y h_y hy设为 m a x ( L i , h y ) max(L_i,h_y) max(Li,hy) h i h_i hi全部处理后贪心确定每个人学到的时间, O ( m l o g ( n ) ) O(mlog(n)) O(mlog(n))

以下是原文

处理数组hi表示i号同学最早在hi+1才可以学会毒瘤算法。对于最终没有学会毒瘤算法的同学,就是∞。对于一对人 x,y,y要么在hx之后和他吃午餐,要么对于所有Rj<hx的边y↔x,hy > Lj。跑一个最短路就可以预处理出h。 我们在知道每个人的hi的情况下,在hi以后的时间段一定越先学习毒瘤算法越好。跑一个带限制的最短路即可,最后如果有最终学会毒瘤算法的同学没有被访问到即无解。


10月31日

真是惨淡呢…

leset

高精度, O ( ? ) O(?) O(?),0分

Stern Brocot 树,可以发现永远不会有约分操作,那就用矩阵快速幂优化一下, O ( S l o g ( n u m ) ) O(Slog(num)) O(Slog(num))

femaledress

网络流算出最大答案, O ( c a n p a s s ) O(can pass) O(canpass),54分

考场上花了半个小时尝试最小割计数

其实最大答案不用网络流,可以直接DFS,每个联通块是树就全选点,或者全选边。统计方案数时,边双联通分量肯定选边,连接多个双联通分量的链/树也必须全部选边,那么实际上贡献答案的是只接在一个双联通分量的树,这上面的方案数可以通过树DP搞出来, O ( m + n ) O(m+n) O(m+n)

envelope

未找到源程序

不会


11月1日

practice

似乎每( [ 1 , k ] [1,k] [1,k]的最小公倍数)个数跳完路程是确定的,且最大不超过 360360 360360 360360,那两头多余部分暴力跳,中间直接算跳过了多少区间, O ( T k ∗ l c m ( [ 1 , k ] ) ) O(Tk*lcm([1,k])) O(Tklcm([1,k])),100分

surmount

暴力,枚举所有情况, O ( s l o w ) O(slow) O(slow),30分

区间DP+背包?见下文

先排序,补t个+∞的炁,最后被使用的炁一定是若干个区间。考虑对这些区间做区间dp,设 f [ l ] [ r ] f[l][r] f[l][r]表示区间 [ l , r ] [l,r] [l,r]的炁被全部使用的方案数和总答案,转移就枚举最后一次使用的炁 k k k,那么左右方案数是 f [ l ] [ k − 1 ] f[l][k-1] f[l][k1] f [ k + 1 ] [ r ] f[k+1][r] f[k+1][r],最后一次能选的数是 ( a l − 1 , a k ] (a_{l-1},a_k] (al1,ak],再乘个组合数就行了,最后把这些区间再做个背包。

pos

题目是这样说的

若Alseo Roplyer能保住受伤部位的所有真气不受毒素污染,他就能使出太乙神功,为自己续上一命,否则就 将武功尽废,命丧黄泉。现在急的团团转的Tak-Vin想要你告诉他Alseo Roplyer是否能续命成功,若能成功,最少需要多少秒。

那没有毒气的时候为什么要操作一番

k = 0 k=0 k=0部分分,参照Bzoj 1189 O ( ? ) O(?) O(?),30分

可以在那部分分基础上判断毒气到达庇护所的时间


11月2日

stone

似乎是正解, O ( ∑ n ) O(\sum n) O(n),100分

打表或者随便推导一下就能发现必胜和必败状态交替出现且每段数量固定,具体来说是 [ k ∗ ( n 3 − 2 n + 1 ) + n , k ∗ ( n 3 − 2 n + 1 ) + n 2 − 1 ] [k*(n^3-2n+1)+n,k*(n^3-2n+1)+n^2-1] [k(n32n+1)+nk(n32n+1)+n21]这些段必败,其它段必胜,枚举每个块大小,只要有一个块必胜就行了, O ( ∑ n ) O(\sum n) O(n)

matrix

暴力, O ( q n 2 ) O(qn^2) O(qn2),10分(话说为什么过不了操作没有重合的部分分)

发现每种操作只会更改正方形边缘上的点和外边一圈的点的相邻格子,而内部的点相邻关系不会改变,所以每个点开两个 p a i r < i n t , i n t > pair<int,int> pair<int,int>来维护上下/左右(两个 p a i r pair pair不区分)的点是什么,每次只用暴力更改边缘的点的 p a i r pair pair即可,考虑如何确定 p a i r pair pair表示上下还是左右,可以维护每行每列第一个点是什么,这个可以暴力维护,由于在最前端的 p a i r pair pair里必定有一个是 0 0 0,就可以确定这列都有些啥了, O ( q n ) O(qn) O(qn)

tree

未找到源程序

不会


11月3日

neworld

SPFA, O ( v e r y   f a s t ) O(very \ fast) O(very fast),100分

merging

状压DP,维护每个分界线的状态,转移很烦, O ( n m 2 2 m − 2 ) O(nm2^{2m-2}) O(nm22m2),100分

似乎只维护每一块第一个会方便很多, O ( n 2 2 m − 2 ) O(n2^{2m-2}) O(n22m2)

raytracing

未找到源文件(没时间写)

离散化所有斜率,用线段树维护每段斜率被哪个障碍物覆盖,横轴和竖轴分开做,选横坐标小的就好了

有一个数轴,范围为0°~90°,其中位置为?°的点对应一个值,即动点前进方向与x轴夹角为?°时最早遇到的障碍物编号。这样每个长方形是不是就对应着轴上的一段区间了?可是如何维护长方形之间的互相“遮挡”关系呢……?由于从摄像机的视角“看”长方形,永远只能看到较近的两条边,那就只考虑这些线段;再把它们分成横边与竖边,这样一来,对于横边(或竖边),y(or x)坐标更小的线段就肯定能在它所对应的数轴区间里遮挡住y(or x)更大的线段了。先把所有向量按与x轴的夹角排序,进行离散化,然后便是两个区间更新最小值、单点查询的问题了。用你喜欢的数据结构(比如线段树)维护一下就好啦!


11月4日

yinglong

随机化 1000 1000 1000次左右,先把排队序列随机打乱,然后枚举每一只应龙,贪心在图上选择飞行路径, O ( 1000 n ) O(1000n) O(1000n),100分

behemoth

暴力枚举每把钥匙给哪只贝希摩斯,然后统计答案, O ( n 2 n ) O(n2^{n}) O(n2n),30分

给每一只贝希摩斯建一个带权点,其点权表示选了这只后可以减少多久的开门时间,线段上有 2 n 2n 2n个端点,枚举每个线段,若左右同为起点,则给左边的点加上 r − l r-l rl的点权,同为终点同理,左边终点右边起点必然直接造成贡献,左边起点右边终点,若同属一只,其点权加上 r − l r-l rl,否则连接这两只贝希摩斯,边权为 r − l r-l rl,表示同时选俩只才有贡献,发现这图由多条链组成,在链上DP即可, O ( n 2 ) O(n^2) O(n2)

amaterasu

枚举天照每个技能的体力花费,排序后选第 k k k大的, O ( q n m ) O(qnm) O(qnm),30分

将天照的所有物攻 y i y_i yi全部加入 t r i e trie trie树,每次查询从高到低枚举魔攻 x i x_i xi,根据当前位左右儿子的孙子数量来决定往左还是右走,走到 t r i e trie trie最下面即可, O ( 32 ∗ n ∗ q + 32 ∗ m ) O(32*n*q+32*m) O(32nq+32m)


11月5日

yukionn

预处理 n x t [ i ] [ 0 / 2 ] nxt[i][0/2] nxt[i][0/2]表示又御灵士/雪女飙车时城市 i i i的下一个目的地,每次询问按题意爆搜, O ( n 2 + n m ) O(n^2+nm) O(n2+nm),70分

考虑倍增,可以预处理 n x t [ i ] [ 0 / 1 ] nxt[i][0/1] nxt[i][0/1]预处理同上, p l a [ i ] [ j ] pla[i][j] pla[i][j]代表从 i i i出发,(御灵士走完、雪女走完) 2 j 2^j 2j轮,所达到的目的地。 d i s 1 [ i ] [ j ] ] dis1[i][j]] dis1[i][j]]代表从 i i i出发,(御灵士走完、雪女走完) 2 j 2^j 2j轮,雪女所经过的距离。 d i s 2 [ i ] [ j ] dis2[i][j] dis2[i][j]代表从 i i i出发,(御灵士走完、雪女走完) 2 j 2^j 2j轮,御灵士所经过的距离,每次询问从 2 20 2^{20} 220步向下枚举,距离小于 x x x就倍增跳跳一次, O ( m l o g ( n ) + n l o g ( n ) ) O(mlog(n)+nlog(n)) O(mlog(n)+nlog(n))

goblin

胡乱DFS加剪枝, O ( ? ) O(?) O(?),65分

考虑状压DP, d p [ i ] [ j ] dp[i][j] dp[i][j]表示已经哥布林已经连接完集合 i i i里的点,当前生成树的深度为 j j j时的最优解,每次枚举一个集合 i i i和其子集 s s s,若其子集里的点均有边连向 i s i^s is的点,就为这些点分别找一条最小的由 s s s连出来的边,设它们权值和为 r r r,则 d p [ i ] [ j ] = m i n ( d p [ s ] [ j − 1 ] + r ∗ j ) dp[i][j]=min(dp[s][j-1]+r*j) dp[i][j]=min(dp[s][j1]+rj)。当一个 i i i s s s转移过来,但它们之间的边不是由 s s s里深度最深的点连过来的,那么一定存在另外一个子集 s s ss ss,通过 s s ss ss转移过来的一定是最小值,所以不会漏解, O ( 3 n n 2 ) O(3^{n}n^{2}) O(3nn2)

hestia

暴力枚举每只赫斯提亚站位,更新最大值, O ( n ! ) O(n!) O(n!),30分

简要题解

考虑两个赫斯提亚站位,若 1 1 1站前面答案不劣当且仅当 m a x ( a 1 , b 2 ) < = m a x ( a 2 , b 1 ) max(a_1,b_2)<=max(a_2,b_1) max(a1,b2)<=max(a2,b1),但是直接排序没有传递性,所以必须分段排序,即 a i < b i & a j < b j / a i = b i & a j = b j / a i > b i & a j > b j a_i<b_i \& a_j<b_j/a_i=b_i \& a_j=b_j/a_i>b_i \& a_j>b_j ai<bi&aj<bj/ai=bi&aj=bj/ai>bi&aj>bj三段,第 1 1 1段按 a a a升序,第 2 2 2段随便玩,第 3 3 3段按 b b b降序,而且第 1 1 1段放第 2 2 2段前,第 2 2 2段放第 3 3 3段前肯定不劣,然后直接计算最大值, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

详细题解

明显 c i c_i ci是逐渐递增的。我们用相邻交换法考虑。设某个位置上的赫斯提亚编号为 i i i,后面一只赫斯提亚的编号为 j j j。设 i i i前面所有赫斯提亚的 a a a值之和为 x x x i i i前面那一只赫斯提亚的 c c c值为 y y y。若不交换,则 c c c值较大的赫斯提亚的 c j c_j cj

m a x ( m a x ( y , x + a i ) + b i , x + a i + a j ) + b j m a x ( m a x ( y , x + a i ) + b i , x + a i + a j ) + b j max(max(y,x+a_i)+b_i,x+a_i+a_j)+b_jmax(max(y,x+ai)+bi,x+ai+aj)+bj max(max(y,x+ai)+bi,x+ai+aj)+bjmax(max(y,x+ai)+bi,x+ai+aj)+bj

化简后为

m a x ( y + b i + b j , x + a i + b i + b j , x + a i + a j + b j max(y+b_i+b_j,x+a_i+b_i+b_j,x+a_i+a_j+b_j max(y+bi+bj,x+ai+bi+bj,x+ai+aj+bj

同理,这两只赫斯提亚交换后, c c c值较大的赫斯提亚的 c i c_i ci

m a x ( y + b i + b j , x + a j + b i + b j , x + a i + a j + b i ) max(y+b_i+b_j,x+a_j+b_i+b_j,x+a_i+a_j+b_i) max(y+bi+bj,x+aj+bi+bj,x+ai+aj+bi)

假设不交换更优,则有

m a x ( y + b i + b j , x + a i + b i + b j , x + a i + a j + b j ) ≤ m a x ( y + b i + b j , x + a j + b i + b j , x + a i + a j + b i ) max(y+b_i+b_j,x+a_i+b_i+b_j,x+a_i+a_j+b_j)\leq max(y+b_i+b_j,x+a_j+b_i+b_j,x+a_i+a_j+b_i) max(y+bi+bj,x+ai+bi+bj,x+ai+aj+bj)max(y+bi+bj,x+aj+bi+bj,x+ai+aj+bi)

发现两边都有 y + b i + b j y+b_i+b_j y+bi+bj,则可以消去,因为它对我们的贪心策略没有影响,消去后有:

m a x ( x + a i + b i + b j , x + a i + a j + b j ) ≤ m a x ( x + a j + b i + b j , x + a i + a j + b i ) max(x+a_i+b_i+b_j,x+a_i+a_j+b_j)\leq max(x+a_j+b_i+b_j,x+a_i+a_j+b_i) max(x+ai+bi+bj,x+ai+aj+bj)max(x+aj+bi+bj,x+ai+aj+bi)

然后可以把 x x x消去:

m a x ( a i + b i + b j , a i + a j + b j ) ≤ m a x ( a j + b i + b j , a i + a j + b i ) max(a_i+b_i+b_j,a_i+a_j+b_j)\leq max(a_j+b_i+b_j,a_i+a_j+b_i) max(ai+bi+bj,ai+aj+bj)max(aj+bi+bj,ai+aj+bi)

再进行化简:

m a x ( b i , a j ) + a i + b j ≤ m a x ( b j , a i ) + a j + b i max(b_i,a_j)+a_i+b_j\leq max(b_j,a_i)+a_j+b_i max(bi,aj)+ai+bjmax(bj,ai)+aj+bi

移项:

m a x ( b i , a j ) − a j − b i ≤ m a x ( b j , a i ) − a i − b j max(b_i,a_j)-a_j-b_i\leq max(b_j,a_i)-a_i-b_j max(bi,aj)ajbimax(bj,ai)aibj

观察左式, a j a_j aj b i b_i bi中大的数被消掉了,只剩下 a j a_j aj b i b_i bi中较小数的相反数,用数学语言表述出来就是 − m i n ( a j , b i ) -min(a_j,b_i) min(aj,bi),那么③式可以变成:

− m i n ( a j , b i ) ≤ − m i n ( a i , b j ) -min(a_j,b_i)\leq-min(a_i,b_j) min(aj,bi)min(ai,bj)

再把负号处理掉:

m i n ( a i , b j ) ≤ m i n ( a j , b i ) min(a_i,b_j)\leq min(a_j,b_i) min(ai,bj)min(aj,bi)

似乎我们得到了贪心的排序算法

……

但是直接照这个式子排序贪心选是错的,因为这样做是没有传递性的

反例input:

2
7 6 3 1 1 7 3 1 1 1 6 1 1 6 10
7 6 10 1 1 6 3 1 1 7 3 1 1 1 6

(错误程序)output:

33

26

显然两组输入是相同的(黑人问号)

可以发现,大概应该和 a a a b b b的大小关系有关( a i a_i ai b i b_i bi哪个大)。还有,要使一个数排在前面,那么 a a a越小越好, b b b越大越好。我们先按 a a a b b b的大小关系把所有数据分为三大组,然后开始讨论:

1.当 a i < b i a_i<b_i ai<bi a j < b j a_j<b_j aj<bj时, a i ≤ a j a_i\leq a_j aiaj,应该按 a a a升序排序( a i a_i ai a j a_j aj相等时无所谓);

2.当 a i = b i a_i=b_i ai=bi a j = b j a_j=b_j aj=bj时,爱怎么排怎么排;

3.当 a i > b i a_i>b_i ai>bi a j > b j a_j>b_j aj>bj时, b i ≥ b j b_i\geq b_j bibj,应该按 b b b降序排序。

那么这三大组之间应该怎样排序呢?

1组和2组,1组在2组前肯定能保证满足条件。 2 2 2组和 3 3 3组, 2 2 2组在 3 3 3组前面肯定能保证满足条件。那么 1 1 1组在前, 2 2 2组在中, 3 3 3组在后,是肯定能保证满足要求的。

我们令 d i = a i − b i ∣ a i − b i ∣ d_i=\frac{a_i-b_i}{|a_i-b_i|} di=aibiaibi,那么 1 1 1组的 d d d值为 − 1 -1 1 2 2 2组为 0 0 0 3 3 3组为 1 1 1

于是我们得到了最终的排序条件:先按 d d d值排序;然后若 d d d值小于等于 0 0 0,按 a a a升序排序(这里把 2 2 2组归入1组);若d值大于 0 0 0,则按 b b b降序排序。 这样就可以满足传递性了, O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))


11月6日

picture

暴力写挂, O ( w 2 h 2 ) O(w^2h^2) O(w2h2),0分

来自O的题解, O ( m a x ( w 1 h 1 , w 2 h 2 ) ) O(max(w1h1,w2h2)) O(max(w1h1,w2h2))

我们对第一个矩阵求二维前缀和,便于子矩阵询问。 枚举第二个矩阵的每一块,放大以后铺到第一个矩阵上,把第一个矩阵分成 8 8 8个部分:全被覆盖的,只覆盖了某一边的,只覆盖了某个角的 。把这 8 8 8个部分分别求一个子矩阵和即可

color

未找到源文件

这O说的啥…, O ( n l o g ( n ) + m l o g ( n ) ) O(nlog(n) + mlog(n)) O(nlog(n)+mlog(n))

可以发现对于每种颜色,我们找到最远的两个点,那么这条链上出现过的其他颜色必须在这个颜色之后染,把这个关系建成一张图,跑拓扑序即可。考虑优化建边的过程,我们发现建边是往一条链上所有点建边,用倍增优化建边复杂度

count

打表找规律, a n s = n ! m ! ( n m ) ! ( n + m − 1 ) ! ans=\frac{n!m!(nm)!}{(n+m-1)!} ans=(n+m1)!n!m!(nm)! O ( n m ) O(nm) O(nm),100分

O的题解提到了这玩意儿,但是没有证明…

考虑另外一个做法, O ( n m ) O(nm) O(nm)

考虑从大往小放数,每次放一行或者一列。 记 f [ i ] [ j ] f[i][j] f[i][j]表示放了 i i i j j j列的方案数,转移时枚举剩余的最大值新增一行还是一列,那么这一行/一列剩下的位置随便放。 例如假设放了新的一行,那么方案数会乘上这一行放哪的 i + 1 i+1 i+1,这一行内部排列的 j ! j! j!,这一行选除了最大值外剩余的数的方案 C ( n m − i j − 1 , j − 1 ) C(nm-ij-1,j-1) C(nmij1,j1)


11月7日-11月8日

咕咕咕


11月9日

刷水,最后的挣扎


淡看人间,森罗万象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值