牛客挑战赛51
-
A
见过的最恶心的 (A) 之一了,居然限制不能相等,那么只好跑一个根号的做法了
-
B
一个显然的贪心是先把每个联通块先喂饱,然后按照联通块涉及的点数排序,逐个合并并喂饱
那么如上过程预处理出来每个状态需要几条边,查询二分即可
-
C
(log n) 处理出来当前数是从 (1) 开始的第几个回文数
剩下计算从 (1) 开始第 (k) 个回文数是几即可
-
D
设 (dp[i][j]) 表示母串长度为 (i) 时匹配到模式串第 (j) 个的答案数,那么总答案即 (sum_i dp[m][i])
转移是固定的,先处理出来一个 (fail) 然后就能统计最优情况下向哪里转移,如果到 (n) 就给答案加上 (1),也就是把矩阵扩展到 ([n+1,n+1])
注意两个限制可能在同一个位置,细节比较多
-
E
不难得到这样一个式子:(varphi=id* I)
那么用该式把式子推一推有
除法表示整除,那么又变成了 ( m{SDOI}) 旧试题,枚举 (lcm) 来连边,冲三元环计数即可
mod
一定要是 const
呀!本题卡常严重
-
F
考虑枚举一个长度为 (i) 的链,并且这些点的标号为 ([n-i+1,n])
这种标号只是为了保证在使用 ( m{prufer}) 序列的过程中这些点不会被删掉,最后肯定要乘 (A_n^i)
那么 ( m{prufer}) 序列上剩下的位置有 (n-i) 个,除了最后一个位置的点的个数是 (i),剩下的 ([1,n]) 随便填,那么再计算个贡献,总答案是:
[n^mn!+sum_{i=1}^{n-1} A_n^i i^{m+1} n^{n-i-1} ]不太懂呀,这个 (nlog n) 咋过的 (1e7) 呀!
-
G
假装自己会这个题了
AGC013D
上来先读错题,这是合理的 ( m{color{grey}yspm}) 吗
- 我会入门 ( m{dp})
不难设计一种 (dp):(f[i][j]) 表示第 (i) 次过后其中一个球 (j) 个的方案数(两个球地位相同)
转移枚举下一个操作的方式:( m{RB,BR,RR,BB}) 同时要判断边界
- 我会注意重复
上面提到的转移如果把 (j) 放到坐标系上,任意平行的折线得到的序列都是一样的
那么按照一些题目的套路是定义新的 (g[i][j]) 表示中途出现过最小值的方案,(f)
变成了没有出现过的方案
转移貌似仍然是枚举下一个球放在哪里,式子比较好说
AGC013C
考虑物理中的弹性碰撞:两个物体的动能不变,动量也不变
那么该性质运用到本题中不难发现:蚂蚁的相对位置不变
不难发现所有蚂蚁的最终态是可以直接计算的,也就是 pos+fl*time
那么要求每个蚂蚁的部分就是要确定第一只蚂蚁的位置
设顺时针为正,一开始第一只蚂蚁的位置为 ( m{rank} 1),那么一个蚂蚁穿过正向该位置会使第一只蚂蚁的排名增加,反向会减小
这个原因貌似需要花时间模拟和猜测,同时有一点点细节:负数坐标要根据是不是 (len) 的倍数让 ( m{rank}) 特殊 (+1)
正数不需要处理的原因也值得思考一下
LOJ2880
一开始想到了维护斜率等等容斥的方法,但是发现都并不能实现
考虑按照 (x) 这维排序然后冲 ( m{cdq}) 分治的做法,那么要统计的是左边的点在右边的形成的合法矩形
这时候已经保证 (x) 大小固定了,如果两边都满足 (y) 这维上单调,那么可以维护一个单调栈
一种统计的方式是维护 (y) 单调递减的左边单调栈里面 (x) 递减,右边递增
那么合法的部分不难在单调栈里面二分找到,所以复杂度 (Theta(nlog n))
AGC027E
这题做法给我震撼到了,这就是 ( m{AGC}) 吗?
将 (a) 设为 (1),(b) 设为 (2),根据题目中的操作不难发现字符串的和 (mod 3) 是不变的
那么 (s) 通过一定方法能转化成的字符串 (t) 满足如下:
-
(s) 中有相同的字符,否则直接特判 (1) 即可
-
(s) 可以划分成 (s'_ 1s'_ 2dots s'_{|t|}s'_{rem}),使得 (f(s'_ i)=t_i,f(s_{rem})=0)且这些 (s'_ i) 长度不为 (1) 的子串中均有相同字符
其中 (f(str)) 表示 (str) 字符串的数字和
如上便可以使用子序列自动机找到下一个和为 (1/2) 的位置做一个计数 (dp),时间复杂度 (mathrm{Theta(n)})
AGC027D
一开始想到一个 (x,x+1,2x+1,(x+1) imes (2x+1)+1) 的构造方式,但是发现完全不行
手玩 (n=3) 的部分发现这个乘积可以加可以减,写个 ( m{AI}) 出来没准能做
但是不难发现 (x=2) 时 (n=60) 左右 ( m{AI}) 都救不了了
考虑到本题中矩阵是当前点和对角相邻的点是相互独立的,那么还是设 (mod) 的值是 (1)
那么给每个对角线赋上一个互不相同质数作为权值(主对角线和其它对角线都要给)
那么对角线交点的相邻点直接取它的相邻点的 (lcm+1) 即可
注意:每个对角线附的权值貌似需要谨慎考虑,是 ({a_n,a_1,a_{n-1}dots}) 的格式
HNOI2015 接水果
考虑路径的包含的条件,分为是 ( m{lca}) 是路径端点和 ( m{lca}) 不是路径端点两种情况
考虑直接分治套扫描线的朴素做法,solve(l,r,st,ed)
表示权值离散化后在 ([l,r]) 的部分回答在 ([st,ed]) 之间的询问
使用树状数组来维护点权,那么按照下面几个题的套路分治实现即可
在初始化扫描线的时候(端点是 ( m{lca}) 的情况),处理 ( m{1 o dfn[son]-1}) 的部分和 ( m{dfn[son]+1 o n}) 的部分的 (x,y) 坐标上的数值是明显不同的
因为在询问点中满足 (dfn[x]le dfn[y]) 那么矩形添加要保持一致
Codeforces1019E
将所有路径变成一次函数放到平面直角坐标系中,要做的工作就是将直线的函数值取 (max),不难发现得到的是一个下凸壳
根据半平面交凸包对偶的知识,求解如上问题可以变成维护 ((a,b)) 的一个上凸包
考虑边分治中合并信息这一过程,本质上是让两侧路径的 (a,b) 进行加和,确实是一个闵可夫斯基和的式子
那么在边分治的过程中维护所有的路径的闵可夫斯基和即可,这样保留了有效信息,降低了时间复杂度
BZOJ2870
没错,这将会是一个简短的边分治学习笔记
边分治就是先进行三度化来保证复杂度,剩下的和普通点分治类似
下附三度化的精巧实现:
inline void dfs1(int x,int fat){
for(reg int i=head[x];i;i=e[i].nxt){
int t=e[i].to; if(fat==t) continue;
a[x].push_back(t); dfs1(t,x);
} return ;
}
inline void rebuild(){
For(i,1,n) head[i]=0; cnt=1;
for(reg int ls,rs,i=1;i<=nds;++i){
if(a[i].size()<=2) for(auto p:a[i]) adde(i,p,p<=n),adde(p,i,p<=n);
else{
ls=++nds,rs=++nds; val[ls]=val[rs]=val[i];
adde(i,nds,0); adde(nds,i,0); adde(ls,i,0); adde(i,ls,0);
int cur=0; for(auto x:a[i]) if(cur&1) a[rs].push_back(x),cur^=1; else a[ls].push_back(x),cur^=1;
}
} return ;
}
本题如上处理之后,对于当前分治边 (x),从大到小枚举一侧的点集,在另一侧使用单调指针维护点权不小于其的最长边更新答案
对于另一侧的点集也可以使用相同枚举
ZJOI2016旅行者
很有意思的分治,这种普通分治在考场上确实不大好直接得到做法
设当前分治区间 ([x_1,y_1,x_2,y_2]) 同时长大于宽(宽大于长也同理),取长中点的边跑 ( m{Dijsktra})
每次更新跨过中边的答案,剩下的询问进行递归
貌似时间复杂度 (Theta(sqrt{nm}(nmlog nm+q))) 很虚,甚至 (Luogu) 不 (O_2) 过不去
Codeforces833D
树上路径问题,还是点分治,问题变成如何维护子树信息
题目限制为 ((A+a)in [frac12,2] (B+b)),不难想到使用 ( m{BIT}) 差分式子然后维护
那么本题剩下的就是代码实现了
Codeforces1338E
本题需要若干引理,刷题还需谨慎考虑
题目里面的图形给强联通图带来了若干奇妙性质
- 任意 (dis(i,j)) 在联通的状态下不超过 (3)
反证,如果大于 (3) 则存在路径 (p_1 o p_2cdots p_5) 满足前面的点没有向后面的点的连边,((p_1,p_3,p_4,p_5))构成题设图案
- 对原来的图形进行强联通分量缩点,那么仅有最后一个强联通分量里面的点数可能多于 (1)
考虑到竞赛图没有二元环,那么点多了任意一个三元环都可以和后面的点构成题设图形
对原图进行拓扑排序,能扩展的点给答案带来的贡献即 (614n+1) imes exttt{后继点数})
加上的 (1) 是由于拓扑序,边必然都是它向后面的点连边
这部分是易于统计的
那么下面的讨论围绕最后一个强联通分量展开,不要着急,还有五个性质没有证明
设最后一个强联通分量里面度数最大的点是 (x),设 (P) 为指向 (x) 的点和 (x) 的并集,(Q) 为 (x) 的出点集合
- 集合 (P,Q) 里面均没有环
因为没有环,那么可以拓扑排序,设 ({p},{q}) 表示上述集合元素按照拓扑序得到的结果,设 (inQ(p_i)) 表示在 (Q) 中边是指向 (p_i) 的点集,同理 (inP(q_i))
- (inQ(p_i),inP(q_i)) 是序列的一个后缀,同时满足 (|inP(q_i)|ge |inP(q_{i+1})|,|inQ(p_i)|ge |inQ(p_{i+1})|)
仍然是反证,除了 (inP(q_i)) 的后缀性需要讨论是不是空集之外别的都是简单画图
- (dis(p_i,q_j)=3 forall p_iin P,q_i in Q)
分类讨论两点间便边的指向,使用 (x) 的度数最大的性质
实现有些简化的计算,因为都是后缀,那么如果两个 (inP/inQ) 是相同的话,可以直接判断元素数量
每个相异集合里面的元素的贡献是 (3)
相同元素且相同 (inP/inQ) 的贡献是 (4),不同 (inP/inQ) 的贡献是 (3)
Codeforces603E
存在满足每个点的度数都是奇数的方案的充要条件是所有联通块大小都是 (even)
证明很简单,每条边带来的度数贡献都是偶数,而一个大小为奇数的联通块里面每个点的的度数和为奇数,矛盾
另一个方向的推导考虑剥叶子,先构造一个生成树,如果一个点有 (even) 个直接儿子,那么父边不保留,最后对于根而言,因为有 (odd) 个数的度数是 (odd) 了,最后一个也是 (odd)
考虑使用 (LCT) 维护联通块的大小,维护虚子树信息是十分简单的
如果在加边的过程中产生了环,那么可以把环上面最大权边删掉,正确性在于又更新了最小生成树的形态,其它其实不变
用优先队列存下来每个在 (LCT) 上的边是不是可以删掉,能删就删,不能删那么最小限制就是该值
骰子
按题解把范围转成 ([0,k))
设 (i) 个骰子出 (j) 的方案数是 (f[i][j]),那么 (frac{1-(sum f[n][i]^2)^R}2) 是答案
不难发现这个平方和本质是 (f[2n][n(k-1)])
证明考虑 (f[2n][x]=sum_{j+i=x}f_{n,i} imes f_{n,j}),把 (i) 换成 (n(k-1)-i) 就能的到了
处理这个一个的想法是整个 ( m{OGF}) 然后多项式快速幂得到每个值的方案数
但是问题本质是整数划分,同时限制变量的大小,那么枚举 (k+1) 大小的变量有多少然后插板就能得到,也就是
稍微注意一下组合数处理别 ( m{MLE}) 就行了
Loj2733
不易发现如果两边各取到的区间价值和不超过各自的 (50\%) 那么直接选一个学校一定更优秀
那么不难发现一个学校里面会取 (ge 50\%) 的价值,故前缀和大于一半的第一个点必然选上
那么枚举 (b) 序列里面右端点,根据若干个类似枚举区间的方式,现在线段树上叶子插入 suma[n]-sumb[l-1]
之后根据单调栈的弹栈把非法的贡献消除掉就行了,如果完整理解了细节不多
Codeforces989E
不难发现点对之间形成了一个完全图,那么通过找直线,然后计算概率的方法可以得到 (P[x][y]) 表示 (x) 走 (1) 步到 (y) 的概率
设 (f_{i,j,k}) 表示 (i) 走 (k) 步能到 (j) 的概率,这个可以矩阵快速幂来做,那么考虑起始点是只被一个直线包含的
如果在直线的交点上面就随机找一个点走出去,平均值不优于最大值,所以跑出来 (bas^{m-1}) ,这里需要行向量乘矩阵的那种处理方式
剩下就枚举点在哪个直线上面,找最大值即可
实现比较阴间,需要实现分数来表示直线和去重,否则各种爆精度
Codeforces1349D
设 (E_x) 表示游戏结束时所有饼干都在 (x) 手上时时间的期望,(P(x)) 表示游戏在 (x) 手上结束的概率
定义 (E'(x)) 表示只有在 (x) 手上时游戏可以结束的情况下结束时间的期望
看起来十分相同,但是前者不会计算在其它人手上游戏结束的情况,而后者会使用一定的代价,将已经到另一个人手上的所有饼干拿到手
设 (f_i) 表示一个人当前局面有 (i) 个饼干到拥有所有饼干的方案
那么不难发现 (f_0) 是上面提到的 (E,E') 之间的差
也就是满足 (E(x)=E'(x)-sum_{j e x}P_j imes f_0-E_x)
移项,把两边全部求和之后发现答案只和 (E(x),f_0) 相关
考虑 (f(i)) 的求解直接分当前人的丢失获得情况乘相应的概率不难得到一个带状矩阵的形式
也就是 (f_i) 只和 (f_{i},f_{i+1},f_{i-1}) 有关,那么发现这个带状矩阵系数能构造出来直接消主元 (0) 的情况
而对 (f_i) 差分得到一个可以线性推的东西,线性推出来即可
本文是博主写的,定义或者含义推导会相对详细,基础数数就不乱写了
Codeforces618G
设 (a[i][j]) 表示长度为 (i) 的网格中出现数字 (j) 的概率,(b[i][j]) 表示长度为 (i) 的网格中第一个数字为 (2) 后出现 (j) 的概率
再设 (A[i][j]) 表示恰好第 (i) 个数是 (j) 的概率(从右往左),(B[i][j]) 类似
不难得到如下等式:
含义就是考虑先在这些格子里构造出来一个 (j-1) 放着占一个格子,剩下的格子还需要整一个 (j-1) 出来,那么就是子问题了
这部分的边界是 (a_{1,1}=p,a_{1,2}=b_{1,2}=1-p)
按照至少两个题出现的思路:(p) 次数多了就跟答案无关了,不难嫖出来这个界是 (50)
计算答案考虑如下 (dp[i][j]) 表示从右向左 (i) 个位置是 (j) 时,后面这些数的期望和
(j=1) 时需要先用一个 (2) 当一下墙后面可以随便整,(j=1) 的时候右边的数不能 (le j)
那么式子也就很显然了:
把 (50 imes 50) 的矩阵按照各自的系数转移出来,带的常数用 ( m{mat(0,x)=x}) 来转移就行了
为了统计答案,最后拿 (dp[50]) 转移的时候把 (dp[50][0]) 先设成 (1)、
BZOJ2655
设 (f_i) 表示序列长度为 (i) 时所有序列权值乘积的和,枚举最少有多少个相同的数字得到:
这里的 ((j-1)!) 是因为考虑在 每 (n) 个数可能会被重复枚举 ((n-1)!) 次,其实就是 (prod_{i=2}^n inom i {i-1})
如果处理出来最后的部分,也就是一个自然数幂前缀和,直接上 (Lagrange) 插值解决即可
很久没有写过插值了,注意 (O(n)) 插值的时候前后缀阶乘要处理正负
Codeforces24D
设 (dp[i][j]) 表示从 ((i,j)) 到第 (n) 行的期望步数,朴素转移是 ( m{trivial}) 的
如果没有左右边界的就少除一个
不难发现这个东西转移是有环的,同时这个系数非常之稀疏,那么每次只用主元消有的就行了
那么就学会了一万年学不会的 ( m{Band Matrix})
Codeforces963E
转移仍然是十分显然的:设 (dp_{i,j}) 表示 ((i,j)) 到外面点的期望步数
考虑主元法:
将每行第一个 (x^2+y^2le R^2) 的点赋标号,按照上式可以得到所有下一行点的关于 (1 o 2R+1) 的系数
不难发现每行里面右侧第一个距离 (>R) 的点的 (dp) 值是个 (0),剩下的直接冲一个裸消元就行了,按照系数回带就能得到 ((0,0)) 的 (dp) 值
那么又学会了一万年学不会的主元法
Codeforces1278F
不难发现每次能让 ( m{Joker}) 在顶上的概率是 (frac1m),枚举有多少次能摸到 ( m{Joker}),使用一些中学数学知识得到
都长成这样了还不去拆 (i^k)?我一拆发现还真能做:
都看到 (inom ni inom ij) 了难道还不去组合意义?我做了一下发现还真行
都组合数加上次方了难道还不配上 (1) 用二项式定理?我用了一下发现还真对
时间复杂度 (Theta(k^2))
本题加强版考虑 (kle 10^7),也就是要求 (Theta(k)) 的做法:
使用容斥的式子把斯特林数展开,剩下的是一个组合恒等变换
回到原式子里面把 (i) 的枚举顺序换到前面去可以得到
其中 (p=frac 1m)
设 (S(i)=sumlimits_{j=0}^{k-i} inom {n-i}j (-p)^j) ,使用杨辉三角能得到一个它的递推式
使用线性筛求得所有的 (i^k) 之后就都能 (Theta(n)) 做了
Codeforces1526E
考虑在 ( m{sa}) 序列上面的相邻两个位置字符,前者为 (i),后者为 (j)
如果满足 ( m{rk_{sa[i]+1}> rk_{sa[j]+1}}) 那么必然有 ( m{s_i<s_j})
据此可以设计一个 ( m{dp:}) (f_{i,j}) 表示当前到了序列 ( m{i}) 位,使用的最大字符集是 ( m{j}),(dp_{i,j}=sum_{j<i m{or} j le i} dp_{i-1,j})
接下来的处理方式确实是各显神通,这里写一个 ( m{Gen Func}) 的做法
直接得到 (dp_1) 的 ( m{OGF}) 为 (frac{1}{1-x}),对于一个 $le $ 的转移不难发现是 (frac{1}{1-x}),而 (<) 的转移是乘一个 (frac{x}{1-x})
这样转移的原因是显而易见的(其实前者直接去掉本身项就成后者了)
对着这个 ( m{GenFunc}) 取第 (n) 项的组合意义便是整数划分,推推式子就能 (Theta(n+k)) 做了