训练纪要贰
安静的开发间接费历史记录。
NOIP-Ax 是大联测,CSP-联x 是小联测,CSP-x 是自己测。
10.3 Thur.
上午模拟赛 \(100+100+100+55\),大联测 RK4,前俩题脑残题,T3 板子题,T4 原题,上个学期打 nfls 打过,改了但是忘了……
下午改题的时候发现自己当时确实理解不透,导致今天还得重新理解一遍。
后来又做了几道板子啊,一个放假前模拟赛放的斯坦纳树的板子,一个放在 vjudge 题单里我忘了自己写过又写了一遍的线段树分裂的板子,还有一个题单里很一眼的树剖。写点水的就写点水的吧。
体活是好的,喜欢打羽毛球,如果之后有大把时间并且没有别人(怕丢脸)的话,想去打篮球了。
机房里闷死了,脑袋疼。
NOIP-A01
A.构造字符串
对于一条限制,相当于两段区间 \([x_i,x_i+z_i-1],[y_i,y_i+z_i-1]\) 内的数对应相等,两个位置 \(x_i+z_i,y_i+z_i\) 的数必须不相等。先把前者并查集处理出来,再把后者当边连上,然后从前往后确定数字,每次相当于是暴力求 \(\operatorname{mex}\)。
B.寻宝
直接搜一遍连通块,然后传送门相当于是连通块之间的单向边。由于 \(k\leq 100\) 而一个连通块可到达的连通块个数不超过 \(k\),所以每次直接暴力搜。
C.序列
对 \(a,b\) 分别前缀和,求 \(\max\limits_{l\leq p_i} (a_{p_i}-a_{l-1})-k(b_{p_i}-b_{l-1}) + \max\limits_{r\geq p_i} (a_{r}-a_{p_i})-k(b_{r}-b_{p_i})\)。
\(p_i\) 有关的消了,剩下关于 \(l\) 和 \(r\) 的分别求,即求 \(\max\limits_{l\leq p_i} k\times b_{l-1}-a_{l-1}\),发现是一次函数的形式,其中 \(k\) 是自变量。
所以扫描线 \(+\) 李超线段树维护,从 \(1\) 扫到 \(p_i\),在 \(p_i\) 处做查询。然后反过来做 \(r\)。
D.构树
首先有扩展 Cayley 公式:\(n\) 个点分为大小为 \(a_1,a_2,\cdots, a_m\) 的连通块,有 \(n^{m-2}\prod {a_i}\) 种生成树。
所以就有 DP 设 \(f_{x,i,j}\) 为以 \(x\) 为根的子树中,\(x\) 所在的连通块大小为 \(i\),选择了 \(j\) 条原树边。转移就是强制选择和强制不选,但是不选的情况就相当于分到了不同连通块,所以之后可能又选上了,所以还要减掉选了的贡献。
考虑优化这个 DP,根据一个大家都说很典所以我也说很典但是实际上除了这个题我没见过的一个转化,将第二维改为 \(0/1\) 表示有没有在这个连通块中选出过关键点,因为选出一个关键点的方案就是连通块大小。然后类似上述转移。
点击查看代码
for(int i=siz[x]-1;~i;--i)
{
for(int j=siz[y]-1;~j;--j)
{
ll x0=f[x][0][i],x1=f[x][1][i];
ll y0=f[y][0][j],y1=f[y][1][j];
//选这条边,贡献到 i+j+1
M(tmp[0][i+j+1],x0*y0%mod);
M(tmp[1][i+j+1],(x0*y1+x1*y0)%mod);
//不选这条边,贡献到 i+j
M(tmp[0][i+j],n*x0%mod*y1%mod);
M(tmp[1][i+j],n*x1%mod*y1%mod);
//不选这条边,贡献减到 i+j
M(tmp[0][i+j],mod-x0*y0%mod);
M(tmp[1][i+j],mod-(x0*y1+x1*y0)%mod);
}
}
P6192 【模板】最小斯坦纳树
设 \(f_{i,s}\) 为使 \(i\) 以及 \(s\) 集合中的关键点相连的最小代价,转移有 \(f_{i,s}+w(i,j)\to f_{j,s}\) 和 \(f_{i,s}+f_{i,t}\to f_{i,s\cup t}\)。
直接转移不太行,发现第一种转移类似松弛操作,所以类似 dij 转移。至于第二种就直接在确定一个 \(f_{i,s}\) 代价不能再小的时候枚举超集转移。
总时间复杂度 \(O(n\times 3^k+m\log m\times 2^k)\)。
P7735 [NOI2021] 轻重边
直接树剖,对轻重边(指树剖的轻重边)分开考虑,将边挂到下方点上。
直接线段树维护重边是否合法;对于轻边,我们记一下它最后一次合法的时间戳,所以还需要对每个点维护它最后一次使与它相连的边都不合法的时间戳。
修改的时候路径所有点的时间戳都要更新,每个链头往上跳经过的轻边也要记一下时间戳,每次更新一条链 \([top_x,x]\) 时 \([hson_{top_x},x]\) 都变的合法,而 \(hson_x\) 变的不合法。另外 LCA 处也不合法。查询直接查。
10.4 Fri.
上午模拟赛 \(100+40+60+25\),小联测 RK2。呃呃,这场题好像挺好的。
感觉很大的问题是不敢想不敢试啊。感觉好多时候都是想到一半不敢接着深挖了。T2 明明不难赛时还是没有大胆做,T3 开始猜出来了那个栈的思路,后面想直接线段树维护区间栈的信息直接合并发现合并不了,在想是不是还要转化一步,结果摆了,尽管再尝试转化也做不出来。
CSP-联02
A.挤压
平方相当于二进制上同时为 \(1\) 的可以相同的两位 \(i,j\) 会有贡献 \(2^{i+j}\)。
设 \(f_{i,x,y,u,v}\) 表示考虑到第 \(i\) 个数,其中第 \(x,y\) 位分别为 \(u,v\) 的概率,即可。
B.工地难题
考虑计算最长连续段长度小于等于 \(k\) 的方案。
总共有 \(n-m\) 个 \(0\) 将 \(1\) 分成 \(n-m+1\) 个段,每个段可空。
先枚举 \(k\),然后容斥一下,枚举至少有 \(i\) 段长度大于 \(k\)。方案是 \({n-i(k+1)\choose n-m} \times {n-m+1\choose i}\),前者是剩下的数的方案,后者是钦定超过的段是哪些段。
所以 \(i\) 是不会超过 \(\min(n-m+1,\dfrac{m}{k+1})\) 的,所以复杂度是调和级数。
C.星空遗迹
好题!先考虑怎么线性做询问,定义 \(A>B\) 当且仅当 \(A\) 能赢 \(B\)。
首先连续的相同元素的个数并不重要,可以看成一个元素。
考虑从 \(l\) 扫到 \(r\) 维护一个栈不断加入元素,使得从栈底到栈顶每个元素都能赢下一个元素,最终的栈底元素就是答案。
就是插入一个数的时候,能被栈顶元素赢的话就把它放在栈顶。因为比方说现在栈顶是 R,下一个元素是 P,那么 R 就输了;但是如果中间有一个 S,那么 S 就可以赢 P 了,R 也就不输了。
我赛时想到这个的思路太抽象(甚至我在解释的时候会提到“护盾”一词),所以没法更严谨的说了,自己意会吧。
接下来肯定要用数据结构来优化这个,直接优化不太现实,但是我们设加入 \(i\) 后栈的大小是 \(f_i\),则 \(f_i\) 为:
解释一下最后一行的 \(f_i-1\),就是将栈顶弹掉了,但是如果此时栈非空那么此时栈顶一定等于要插入的元素,所以相当于元素个数减少了 \(1\)。
那么答案就是最后一个 \(f_i=1\) 的位置。考虑再将与 \(1\) 取 \(\max\) 直接去掉,那么答案就是 \(f\) 值最小的位置。
发现 \(i\) 处会对整个后缀 \([i,n]\) 有贡献,那么 \(i<l\) 对区间 \([l,r]\) 的贡献是一样的,不会有影响。
那么现在问题变成了后缀加,区间查最小值位置,线段树维护。
D.纽带
是因为这个题复杂所以我写的更详细吗?
省流:析合树 \(+\) 区间 DP \(+\) 拉格朗日插值。CF *3500 严格加强。
首先类似析合树,我们要定义一些东西,这些东西不与传统析合树完全相同,所以性质也不与传统析合树完全相同。
定义满足题目中的限制,即满足 \(\forall i\in [l,r],a_i\in [l,r]\) 的段称为连续段。
称不与其它连续段部分相交的段为本原段,所以本原段与其他连续段的关系只能是包含关系。
既然所有的本原段之间只有包含关系,我们就可以将所有本原段拿出来作为一棵树。
将所有本原段进一步分作合点和析点,合点指任取它的连续的几个儿子,总能组成新连续段;析点则是总不能组成连续段。
可并不是所有叶子都是连续段,我们将 \(a_i\not=i\) 的点当做非法叶子,也加入到树中。而 \(a_i=i\) 的点我们定义为析点。
那么合点的儿子只能是析点,因为若合点 \(u\) 有儿子合点 \(v\),则 \(u\) 的其它儿子可以与 \(v\) 的儿子组成连续段与 \(v\) 部分相交。
析点的孩子则既可以是析点也可以是合点,甚至可以是非法叶子,不过每两个合析点中间都至少有一个非法叶子,不然这两个儿子拼在一起就形成连续段了。头尾也必须是非法叶子,不然假设头部是一个连续段,那么除去这个连续段其它的儿子拼起来就会形成一个连续段。
那么我们基本就可以开始 DP 了,不过我们仍无法计算在析点中放入了 \(k\) 个非法叶子这一部分的方案数。
因为它是析点,所以即使几个非空叶子相邻也不能是连续段。所以这一部分的方案数就相当于是长度为 \(k\) 且只有 \([1,k]\) 是连续段的方案数,就是题目中的特殊性质。记为 \(A(x)\),此可以递推计算。
(这里有一段递推 \(A\) 的证明,可我还不懂,估计会摆了。)
然后就可以直接区间 DP 转移了,设 \(f_{l,r,x,s}\) 为区间 \([l,r]\) 为一个合点,其中包含了 \(x\) 个连续段,总共有 \(s\) 个儿子的方案;设 \(g_{l,r,x,s}\) 为区间 \([l,r]\) 为一个析点,其中包含了 \(x\) 个连续段,总共有 \(s\) 个非法叶子的方案。再记 \(F_{l,r,x},G_{l,r,x}\) 分别为 \(f,g\) 忽略最后一维的和。
转移直接区间 DP 枚举区间,然后对于 \([l,r]\) 是合点每次枚举一个 \(k\) 加入一段 \([k,r]\) 的析点,对于 \([l,r]\) 是析点每次枚举一个 \(k\) 加入一段 \([k,r-1]\) 的合析点和一个非法叶子,或者直接加一个非法叶子。
先转移 \(g\) 再转移 \(f\),因为 \(f_{l,r,x,s}\) 会从 \(G_{l,r,y}\) 转移。至于那个 \(m_i\) 的限制,相当于是对于区间 \([l,r](r\leq m_l)\) 可以作为析点的一部分,可不能作为整个析点,也不能作为合点或合点的一部分。所以在 \(r\leq m_l\) 时 \(g\) 不能向 \(G\) 更新,整个 \(f\) 都不能被更新。
还有细节也写一下吧,无论是 \(f\) 还是 \(g\) 向 \(F\) 或 \(G\) 更新时都需要保证 \(s\geq 2\)。初始状态是 \(f\) 为空,\(g\) 最前面放了一个非法叶子,还有当 \(i>m_i\) 时一个点可以作为一个析点。
然后你发现复杂度 \(O(n^8)\) 过不去,考虑再优化一下。
将 \(x\) 那一维去掉,把所有 DP 数组的定义更改为关于 \(x\) 的多项式,例如 \(f_{l,r,s}\) 的 \(i\) 次项系数就是原本的 \(f_{l,r,i,s}\)。发现最多有 \(M=\dfrac{n(n+1)}{2}\) 个连续段,所以多项式是 \(M\) 次的。代入 \(M+1\) 个 \(x\) 进去,就可以拉插确定多项式了。
这个优化相当于是你在 DP 的时候可以不用枚举转移的连续段个数和转移后的连续段个数,这相当于少了 \(n^4\)。但是你要做 \(M+1\) 遍所以又多了 \(n^2\)。最终时间复杂度是不满 \(O(n^6)\)。
至于点值转系数,你可以选择直接对着那个式子暴力卷积,最终是 \(O(m^3)\) 也是 \(O(n^6)\) 的。但当然你可以优化这一部分,不过不是复杂度瓶颈,也不是本题重点了,所以不重要了。
点击查看代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
#define ll long long
using namespace std;
const int N=45,mod=1e9+7;
int n,m,M[N];ll A[825],P[N],I[825],Y[825],ANS[825];
ll f[N][N][N],g[N][N][N],F[N][N],G[N][N],H[825];
inline void Mod(ll &x,int y){x+=y;if(x>=mod) x-=mod;}
inline ll ksm(ll a,int b=mod-2)
{
ll ans=1;for(;b;b>>=1,a=a*a%mod)
if(b&1) ans=ans*a%mod;return ans;
}
signed main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(0);
cin>>n,m=n*(n+1)/2,A[0]=A[1]=P[0]=I[0]=I[1]=1;
for(int i=2;i<=m;++i)
{
A[i]=(i-1)*A[i-1]%mod;
for(int j=2;j<=i-2;++j)
A[i]+=(j-1)*A[j]%mod*A[i-j]%mod;
A[i]%=mod,I[i]=ksm(i);
}
for(int i=1;i<=n;++i) cin>>M[i];
for(int x=1;x<=m+1;++x)//多项式代入值
{
memset(f,0,sizeof(f)),memset(g,0,sizeof(g));
memset(F,0,sizeof(F)),memset(G,0,sizeof(G));
for(int i=1;i<=n;++i)
{
P[i]=P[i-1]*x%mod;
f[i][i-1][0]=g[i][i][1]=1;
if(i>M[i]) f[i][i][1]=G[i][i]=x;
}
for(int len=2;len<=n;++len)//枚举区间长度
{
for(int l=1;l+len-1<=n;++l)//枚举区间左端点
{
int r=l+len-1;//区间右端点
//析点更新
for(int i=l+1;i<r;++i)//枚举最后一次转移,选择一个段 [i,r-1] + 叶子
for(int c=1;c<=r-l+1;++c)//枚举选了多少叶子
Mod(g[l][r][c],g[l][i-1][c-1]*(F[i][r-1]+G[i][r-1])%mod);
for(int c=1;c<=r-l+1;++c)//枚举选了多少叶子
Mod(g[l][r][c],g[l][r-1][c-1]);
if(r<=M[l]) continue;
for(int c=2;c<=r-l+1;++c)
Mod(G[l][r],g[l][r][c]*A[c]%mod*x%mod);
//合点更新
for(int i=l;i<=r;++i)//枚举最后一次转移,选择一个析点 [i,r]
for(int c=1;c<=r-l+1;++c)//枚举选了多少儿子
Mod(f[l][r][c],f[l][i-1][c-1]*G[i][r]%mod*P[c-1]%mod);
for(int c=2;c<=r-l+1;++c)
Mod(F[l][r],f[l][r][c]);
}
}
Y[x]=(F[1][n]+G[1][n])%mod;
//拉插求系数(暴力卷积)
memset(H,0,sizeof(H)),H[0]=1;ll C=Y[x];
for(int i=1;i<=m+1;++i)
{
if(i==x) continue;C=C*I[abs(x-i)]%mod*(x>=i?1:-1);
for(int j=i;~j;--j)
{H[j]=H[j]*(-i)%mod;if(j) H[j]=(H[j]+H[j-1])%mod;}
}
for(int i=1;i<=m;++i) ANS[i]+=C*H[i]%mod;
}
for(int i=1;i<=m;++i) cout<<(ANS[i]%mod+mod)%mod<<' ';
cout<<'\n';return 0;
}
10.5 Sat.
发现开始写训练纪要的确促进我改题了,另一个促进是旁边的 5k 和队奶。
上午把昨天 T4 改了,然后开了道串,被恶心到了,扔了。然后过去了多半个上午了。
后来啊,后来就去看别人游记和自己游记了。
明天下午有 CF Div2,爽了,希望不会出岔子。
下午把昨天 T4 题解补了,但是好像不是很会 \(A\) 怎么推。
怎么又开始摆烂了。晚上拿小号打 ABC。
CF995F Cowmpany Cowmpensation
拉插优化 DP 板子?
简单 DP,设 \(f_{x,i}\) 是 \(x\) 点工资为 \(i\) 的方案数,设 \(g_{x,i}=\sum\limits_{j\leq i} f_{x,i}\),\(f_{x,i}=\prod\limits_{y\in son(x)} g_{y,i}\)。
发现 \(g_{x,i}\) 是关于 \(i\) 的次数为 \(siz_x\) 次多项式,证明考虑归纳。直接 \(O(n^2)\) DP,然后插值求 \(i=D\) 的答案。
P4463 [集训队互测 2012] calc
咕咕咕。
ABC347F Shipping
不难发现一次发出一定是 \(a_i+kx,k\in \mathbb{Z}\) 的时刻,因为你一次发出不然就是可以发出抓紧发出,否则肯定是要等到下一次有新包裹要发出再发出,不然你中间等待没意义。也就是说相当于从一个时刻开始连续发送若干次。
设 \(f_{i,j}\) 为在第 \(i\) 个包裹到达时,总共有 \(j\) 个包裹还没发出时,已发出包裹的发出时间和的最小值。
转移时枚举 \(i,j\),再不断发出包裹,直至没有包裹要发出。每次发出一些包裹,然后时间 \(+x\),再将这 \(x\) 时间内的新到达的包裹数加上,转移到下一个包裹到达时。总时间复杂度 \(O(n^3)\)。
10.6 Sun.
上午模拟赛 \(100+100+0+20\),rk1,T4 本该是 \(5\) 分的。赛时 T2 某个点 .in
和 .ans
放反了硬控我中午吃饭时间。
下午非常好 CF,C1 吃了发罚时,34 min 过完 C2。发现 D 题过得没 E1 多就去做 E 了,想了一会想到 kruskal 重构树,但是想先想 \(n^3\) 就扔了。后来 1h 之间猜了个东西,感觉自己过不去 E3 所以往 E3 交防止自己吃罚时,假了。后来发现 kruskal 重构树上简单 DP 就能做到 \(O(n^2)\) 啊,比较激动先交到 E2 时数组开小了。不过还行啊,终于上回 Master 了!
开始期待下一场 20 号正常点 CF 了,不过我打 Div1 上过分吗?
之后先改 T4 被控了半天,后来发现错了一堆,其中最唐的是叉乘求面积没取绝对值。于是题好像改不完了,这下有事干了。
题解是之后才补得,好水。
折叠起来的一些闲话
最近发现心情并不糟糕了,对奥赛重新乐在其中了。
感觉最大的原因是训 NOIP 没有对自己打击这么大,去年训省选甚至都还好。但是开始训国赛(甚至我没法打国赛)尤其是打 nfls 的时候每天打击就很大了,也是心情最不好的时候。
趁着现在心情好抓紧提升自己吧,省的明年到了那个时候又天天破防,都高二了破防肯定得比高一严重。
其实最近真的能够感觉出来自己在提升,这种感觉是很久没有过的了,这种感觉可能是跟心情好相辅相成的吧。
CSP-09
A.邻面合并
要将一行中的分割线压下来,可以根据分割线解出来唯一的最后一行的连续段分布方式,一个连续段指的是在一行中的在同一矩形中的极长区间。
转移时枚举上一行状态和当前行状态,一个连续段如果在上一行不是连续段就有 \(1\) 的代价。
B.光线追踪
询问向量与矩形只有可能交在矩形的底边或左侧边上,对着两种情况分开考虑。
考虑与底边相交,能与一个矩形相交的斜率是一段区间,同一斜率最先交到的是底边纵坐标最小的矩形。
所以把询问向量的斜率拿出来离散化当做线段树下标,加入矩形相当于区间取 min,查询是单点查最小值编号。
C.百鸽笼
拒绝采样法,每一列进满以后也能进,进去以后相当于要再进一次,与原问题一致。操作序列中最后一个被进满的就是答案。
设 \(g_{x,s}\) 表示 \(s\) 集合中的列都在 \(x\) 之后才被进满,容斥一下就能得到 \(x\) 的答案。
发现容斥系数只与 \(s\) 有关,所以直接修改定义 \(g_{x,i}\) 表示有 \(i\) 个列在 \(x\) 之后被进满的概率。
设 \(f_{x,p,i,j}\) 表示前 \(p\) 个列,有 \(i\) 个在 \(x\) 之后进满,这些列在 \(x\) 进满之前总共进了 \(j\) 个人的方案数。
依次考虑每一列 \(o\) 在 \(x\) 进满之前进了多少人,可以进 \([0,a_o-1]\) 个人,背包转移时乘一个组合数就行。
最后将 \(a_x-1\) 个 \(x\) 插到操作序列中,另一个 \(x\) 要放在最后,乘一个组合数。
这时只考虑了 \(x\) 与这 \(i\) 个列,其他的列没有管,那么这 \(i+1\) 个列中进了 \(j+a_x\) 个人的总方案数就是 \((i+1)^{j+a_x}\),可算出概率。
发现实际上就是把 \(x\) 去除以后做背包,所以可以先做背包再把 \(x\) 去掉来优化复杂度。
D.滑稽树下你和我
计算几何,没啥意思,改了但不写题解。
10.7 Mon.
上午模拟赛 \(100+100+100+50\),rk1。
下午改今天 T4,昨天 T3,在 CF 上发表言论,补一补博客,但是感觉补得很仓促,无所谓了。
huge 说让我和 5k 出一个人当代表发言,rand
输了,都怪涛哥手气差。
NOIP-A03
A.五彩斑斓
枚举矩形的左边界 \(l\) 和右边界 \(r\),再枚举下边界 \(i\),考虑有多少上边界合法。
当 \(a_{i,l}\not=a_{i,r}\) 时,所有 \(i\) 个上边界均合法。
当 \(a_{i,l}=a_{i,r}\) 时,记 \(c_{i,l,r,x}\) 为 \(\sum\limits_{j\leq i} [a_{j,l}=a_{j,r}=x]\),则有 \(i-c_{i,l,r,x}\) 个上边界合法。
B.错峰旅行
扫描线。(我不理解放这个干啥,我打的不是普及组啊?)
C.线段树
记 \(a_{L,R}\) 为 \(\sum\limits_{i=1}^q [l_i\leq L\wedge r_i\geq R]\),直接二维前缀和。
区间 DP,设 \(f_{l,r}\) 为对于所有询问,在 \([l,r]\) 中所需要的最小代价和。有转移 \(f_{l,r}=-a_{l,r}+\min\limits_{k=l}^{r-1} f_{l,k}+f_{k+1,r}\),道理是所有包含 \([l,r]\) 的查询本来是要查两次的,现在只需要查一次了。
D.量子隧穿问题
发现是一个内向基环树森林(我赛时没看出来?)。首先不跟 \(n\) 相连的没啥影响,直接不理。
考虑是树咋做。设 \(p_i\) 是目前 \(i\) 点有猫的概率。
按顺序处理 \(i\to b_i\) 的边,在此之前两点一定不连通,所以概率是独立的,于是可以计算出来合并以后两个点的概率。
考虑原问题的基环树,只需要讨论环上第一次操作的情况,即钦定合并完后 \(i\) 点是否有猫。两种情况分别有一个概率,后面的接着做就行了,最后 \(p_n\) 要乘上你钦定那一步的概率。
CF2021E3 Digital Village (Extreme Version)
其实赛时已经转化完了,但是我并不知道可以用闵可夫斯基和优化 \((\max / \min ,+)\) 卷积。
考虑建出 kruskal 重构树,设 \(f_{i,j}\) 为 \(i\) 子树中选了 \(j\) 个点的答案最小值。记 \(cnt_x\) 为 \(x\) 子树中有多少个关键点,\(w_x\) 为 kruskal 重构树上的权值。
转移时合并两个子树 \(f_{x,i}=\min f{u,j}+f{v_{i-j}}\),还有一种转移是 \(f_{x,i}=f_{v,i}+cnt_{u}\times w_x\),意义是所有左子树中的点都要跑到右子树中去,经过的最大的边权就是 \(w_x\)。另一侧同理。
所以实际上我们每次转移后 \(f_{x,0}\gets cnt_x\times w_{fa_x}\),然后就是 \((\min,+)\) 卷积的形式,显然有凸性,可以闵可夫斯基和优化。
我们考虑记录 \(f_{x,i}-f_{x,i+1}(i\in[0,siz_x-1])\),这个单调递减。每次手动给 \(f_{x,0}\) 赋值时相当于将最大值拿出来加上 \(cnt_x\times (w_{fa_x}-w_x)\),因为修改前的 \(f_{x,0}=f_{u,0}+f_{v,0}=cnt_x\times w_x\),所以需要取出来最大值。于是 set 启发式合并即可,时间复杂度 \(O(n\log^2 n)\)。
10.8 Tues.
别人开学以后就又要跑操了,我还是喜欢没人的学校。
还有你吃饭时间统一改成啥了?建议以后谁定吃饭点谁跟我们一起吃饭,再配个人去查你看你能不能来得及上床。
当然来得及,只是一点别的时间都没有了。
上午模拟赛 \(3+56+100+100\),rk8,哈哈。
发现自己现在还是畏难心里比较严重,是不是应该强迫自己做点难题。
还有感觉现在做的很多题都跟正赛偏不少啊,可能得多刷点更为接近的。
而且他模拟赛这么放,我现在都搞不清楚 NOIP 啥难度,我都没有考场策略了。
但其实对于我不紧张比有策略重要吧,一有策略就容易紧张怎么办?
晚上比较颓啊,明天开个比赛 VP 吧,还没想好是啥我去,有模拟赛啊。
CSP-10
A.欧几里得的噩梦
不喜欢这个题,不想写题解。
B.清扫
先选一个非叶子点当根。从叶子到根合并,当位于 \(x\) 点时,记 \(sum\) 为子树中所有叶子还需要做的操作次数和,如果在 \(x\) 点不做,这 \(sum\) 个操作之后都要经过 \(x\),而现在可以选两个叶子使 \(sum\gets sum-2\) 而 \(a_x\gets a_x-1\)。所以 \(LCA\) 在 \(x\) 处的操作次数是 \(sum-a_x\)。\(a_x<sum\) 或 \(sum>2a_x\) 时不行。记 \(m=\max\limits_{y\in son(x)} a_y\),最多操作次数是 \(\begin{cases} \lfloor\dfrac{sum}{2}\rfloor & m\leq sum-m \\ sum-m & m>sum-m \end{cases}\),\(sum-a_x\) 比这个大也不行,最后 \(a_{root}\not=0\) 也不行。
C.购物
发现当 \(\max\limits_{i\in [1,n]} a_i<k\leq \max\limits_{i,j\in [1,n]} a_i+a_j\),\(\max\limits_{i,j\in [1,n]} a_i+a_j < 2k\)。
进而可以得到 \(\max\limits_{i,j\in [1,n]} a_i+a_j<k\leq \max\limits_{i,j,p\in [1,n]} a_i+a_j+a_p <2k\)。
所以记 \(M=\max\limits_{i\in [1,n]} a_i\),\([M+1,\sum\limits_{i\in [1,n]} a_i]\) 都是合法的,当然 \([\lceil\dfrac{M}{2}\rceil,M]\) 也是合法的。
而当 \(k<\lceil\dfrac{M}{2}\rceil\),一定就跟当前最大值无关了,变成规模为 \(n-1\) 的子问题。求这些区间的并就行。
D.ants
先想到莫队。带 \(\log\) 太无聊了,考虑如何 \(O(1)\) 插入一个数,求值域最长连续段。
记 \(l_i,r_i\) 表示 \(i\) 节点所在连通块的左边界和右边界,发现如果只插入不删除的话,只需要更新 \(r_{l_i}\gets r_i,l_{r_i}\gets l_i\),中间的点可以不用管,因为并不会再用到。于是把莫队改成回滚莫队只插不删就行了。
CF2021D Boss,Thirsty
原来就是直接做啊。
记 \(s_{i,j}=\sum\limits_{k\leq j} a_{i,k}\),设 \(f_{i,x,y}\) 表示第 \(i\) 行选区间 \([x,y]\) 的最大答案,有转移:
设 \(L_{i,l},R_{i,r}\) 分别表示 \(\max\limits_{r\geq l} f_{i,l,r},\max\limits_{l\leq r} f_{i,l,r}\),转移变为:
考虑直接求 \(L_{i,x},R_{i,y}\)
计算四个括号里的东西即可,注意能否取等,这意味着一些计算的先后顺序。第一行要特殊处理。
10.9 Wedn.
昨天晚上听说要买 nfls 题打,你怎么知道我这几天有这个想法。
毕竟这模拟赛吧,也不是很烂啊,只能说每天就随便放一场,好不好听天由命,难不难命中注定。也没什么标准,给我打的挺迷糊的。nfls 可能会好的多吧。
上午模拟赛 \(100+100+100+55\),本校 OJ 跟联训 OJ T1 文件名不一样,这个我确实一点责任没有吧,所以按没挂分算,rk3。T4 挂了 5pts,无足轻重。
下午先写了一会脚本,大概是想要在洛谷似掉的时候自己跳到 vjudge。后来把 T4 改了。
晚上和 K8 due。我:“啥是 due?”,K8:“……咱俩限定一个难度范围……”,开了道 2400,结果是唐题,大概是放模拟赛 T1 大家全都过的题。
感觉有点累,晚上也睡不着觉,歇一会。
快让我打 nfls!
NOIP-A04
A.02表示法
直接递归做,要实现高精右移。
B.子串的子串
我用 SAM 做 NOIP 字符串哈希题。
直接对 \(S\) 建 SAM,考虑从小到大加入 \(endpos\),可以直接暴力跳父亲。设节点 \(p\) 目前最大 \(endpos\) 是 \(f_p\),则 \(p\) 点对答案的贡献是 \(\max(0,\min(f_p-l+1,len_p)-len_{fa_p})\)。对于 \(l\geq f_p-len_{fa_p}+1\) 贡献是 \(0\);对于 \(l\leq f_p-len_p+1\),贡献是 \(len_p-len_{fa_p}\),可以直接记在 \(f_p-len_p+1\) 上,然后做后缀和;对于 \(f_p-len_p+1<l<f_p-len_{fa_p}+1\) 的贡献是 \(f_p-l+1-len_{fa_p}\),这一部分可以直接暴力赋值,或者直接差分一下,总之很好算。
所以说把询问挂在右端点上,加入 \(r\) 这个 \(endpos\) 时暴力跳父亲,把原来的贡献减了,把新的贡献加了。然后直接查询就行了,时间复杂度 \(O(n^2+q)\),快得要死。
C.魔法咒语
考虑正反建出两棵 Trie 树,发现一个合法串可能被计算多次,于是钦定在所有合法方案中第一个串最长的方案中统计答案。算不到单个串的情况,最后单独加上。
所以遍历一棵 Trie 树上的所有节点 \(p\),再遍历所有字符 \(c\)。当 \(son_{p,c}\) 不存在时,它可以选择接上一个起始字符为 \(c\) 的后缀,预先处理一下每个字符有多少个不同后缀即可。
测大样例发现不对啊,有个 Corner Case。发现我们要求非空,所以如果有一个合法字符串 \(A+c\),若 \(son_{p,c}\) 存在,我们就可能漏算。所以当 \(son_{p,c}\) 存在,并且 \(son_{p,c}\) 表示的字符串不在给出的字符串集中,并且有字符串的结尾字符是 \(c\),我们就要将答案 \(+1\)。
D.表达式
当模数较小,可以在线段树上每个节点维护一个映射,表示当值为 \(i\) 时,经过当前区间后,值变为 \(f_i\)。
原题保证了模数分解质因数后质因数个数不多且 \(p_i^{a_i}\) 均不大,所以可以直接对每个 \(p_i^{a_i}\) 做一遍,CRT 合并答案。感觉很无趣。
CF1866L Lihmuf Balling
我不理解啊,这玩意洛谷甚至评了紫,那我还是写一下。
直接枚举 \(k\),每个 \(k\) 最多转 \(\dfrac{\operatorname{lcm}(n,k)}{n}\leq k\) 圈,每圈相当于在一个位置之后都可以取到,解不等式和等差数列求和哪有紫?
10.10 Thur.
没有模拟赛,想开 UNR VP 的。
结果看到官网发了省队名额测算的具体常量值,研究了一会,翻了翻去年成绩,时间就不够了,惋惜啊。
vjudge 图论题单不是很想刷,尽管发现自己平常不做什么图论题,考试一考啥也不会。
但是后来发现实在没意思,先 VP 场 CFDiv1 吧,因为上了 Master 过几天打不了 Div2。
结果给我打破防了,A 题过了以后,B 题绿题就不会!!!扔给涛哥和 luobotianle 一会就过了,这咋整?
其实今天本来打算的就是好好歇歇,没休息好有点难受。
CF1889B Doremy's Connecting Plan
若 \(S_i+S_j\geq i\times j\times k\),则 \(S_i+S_j\geq ijk\geq ij\geq i+j\),则有 \(S_i\geq i\) 或 \(S_j\geq j\),即至少存在一个点可以和 \(1\) 连。
所以只考虑跟 \(1\) 连就行。
CF1889C2 Doremy's Drying Plan (Hard Version)
设 \(f_{i,j}\) 为删除了 \(j\) 条线段且 \(i\) 未被覆盖时,前 \(i\) 个数中未被线段覆盖的最大数量。记 \(g(x,y)=\sum\limits_{i=1}^m [x<l_i\leq y,r_i\geq y]\),则有转移 \(f_{i,j}=1 + \max\limits_{p<i} f_{p,j-g(p,i)}\)。
考虑转变为枚举 \(g(p,i)\),只需要维护包含 \(i\) 的线段中左端点最大的 \(k\) 个,然后在两个之间左端点的 \(g(p,i)\) 是相同的,就变成区间求 \(\max\) 了。
问题转化成区间 RMQ,末尾插入,维护反 ST 表即可。
CF1889D Game of Stacks
好题。
当每个栈大小为 \(1\) 时,连边后是一棵内向基环树,发现肯定是要跑到环上转一圈结束。可以直接把环消去。
扩展到一般情况也是一样的,只需要每次找到环时把环删掉,把环上每个点出度指向的点更新即可。