Logo KSCD_ 的博客

博客

标签
暂无

P12558 题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-06-09 08:16:38

题意

给定两个长为 $n$ 的数组 $a,b$,元素两两不同。$q$ 次询问,每次给出 $l,r$,求有多少大小在 $[l,r]$ 内的集合 $S$ 满足存在排列 $p$,使得 $a_i>b_{p_i}$ 的 $i$ 组成的集合恰为 $S$。$q-1\le n\le 5000$。

题解

首先枚举 $\left|S\right|=x$,考虑如何判断一个集合 $S$ 是否合法。此时令 $S$ 内元素与前 $x$ 小的元素匹配,$S$ 外元素与剩余元素匹配,且两部分均将 $a,b$ 分别从小到大排序后对应位置匹配一定不劣。因此先将 $a,b$ 排序,这样就可以设 $f_{i,j}$ 表示前 $i$ 个数中选进 $S$ 了 $j$ 个,且前 $i$ 个匹配均合法的方案数。转移时枚举第 $i$ 个数的情况,只进行合法转移即可。时间复杂度 $O(n^3)$。

考虑优化这个过程,注意到 $f_{i,j}$ 转移时若令其在 $S$ 内,则要 $a_i>b_j$,否则要 $a_i<b_{x+i-j}$。这里前者与 $x$ 无关,而后者有关,复杂度瓶颈也在这里。若把顺序倒过来,即 $g_{i,j}$ 表示 $[i,n]$ 中有 $j$ 个在 $S$ 外的合法方案数,则令其在 $S$ 外只需 $a_{i}<b_{n-j+1}$,否则需要 $a_{i}>b_{x-n+i+j}$,反而使得在 $S$ 外的判断不再依赖 $x$ 的值了。若能把不依赖 $x$ 值的两部分拼成答案,就可以降低复杂度。

考虑找到一个位置 $p$,使得其为 $a$ 中最后一个满足 $a_p<b_x$ 的位置,此时可以确定 $[1,p]$ 内的 $a_i$ 放到 $S$ 外一定合法,$[p+1,n]$ 内的 $a_i$ 放到 $S$ 内也一定合法,此时只需要保证前面放到 $S$ 内和后面放到 $S$ 外的匹配合法即可,这正是 $f,g$ 的转移中不依赖 $x$ 的那部分。因此只考虑这些限制转移出 $f,g$ 数组,对每个 $x$ 找到对应的 $p$,$\left|S\right|=x$ 的答案即为 $\sum_{j=0}^x f_{p,j}\times g_{p+1,n-i-p+j}$。对答案求前缀和即可回答 $[l,r]$ 的区间询问,时间复杂度为 $O(n^2+q)$。

代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e3+10;
const int mod=998244353;
void add(int &a,int b) {a+=b;if(a>=mod)a-=mod;}
int n,q,a[N],b[N],r[N],f[N][N],g[N][N];
int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	sort(a+1,a+1+n),sort(b+1,b+1+n),f[0][0]=g[n+1][0]=1;
	for(int i=1;i<=n;i++) for(int j=0;j<=i;j++)
	{
		f[i][j]=f[i-1][j];
		if(j&&a[i]>b[j]) add(f[i][j],f[i-1][j-1]);
	}
	for(int i=n;i>=1;i--) for(int j=0;j<=n-i+1;j++)
	{
		g[i][j]=g[i+1][j];
		if(j&&a[i]<b[n-j+1]) add(g[i][j],g[i+1][j-1]);
	}
	int p=0;
	for(int i=0;i<=n;i++)
	{
		while(p<n&&a[p+1]<b[i]) p++;
		for(int j=0;j<=i;j++) add(r[i],1ll*f[p][j]*g[p+1][n-i-p+j]%mod);
	}
	for(int i=1;i<=n;i++) add(r[i],r[i-1]);
	cin>>q;
	while(q--)
	{
		int x,y; cin>>x>>y;
		cout<<(r[y]+mod-(x?r[x-1]:0))%mod<<'\n';
	}
	return 0;
}

【学习记录】莫队

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-06-12 18:11:47

本来想放到数据结构那篇里的,但那篇已经很长了,且感觉莫队不太数据结构,故新开一篇记录。

普通莫队:P1494 小 Z 的袜子

莫队思想为将序列以 $B$ 为块长分块,将所有询问离线下来,以 $l$ 所在块为第一关键字,$r$ 为第二关键字排序,然后依次处理所有询问,维护当前区间的 $(L,R)$,每次暴力移动到目标区间即可。注意移动时要先拓展后收缩,否则会在 $L>R$ 时出现错误。

计算一下移动次数,由于左端点单次移动距离是 $O(B)$ 的,右端点在每个块内会移动 $O(n)$ 距离,因此总移动次数为 $O(qB+n+\frac{n^2}B)$,在 $B=\frac n{\sqrt q}$ 时最优,然而一般直接用 $B=\sqrt n$ 就足够了,复杂度不超过 $O((n+q)\sqrt n)$。之后复杂度分析均使用理论最优块长。

本题中求区间 $\sum \frac{t_i(t_i-1)}2$,其中 $t_i$ 为 $i$ 在该区间内出现次数。这里暴力维护桶,每次修改桶时也修改目前答案即可,修改是 $O(1)$ 的,可以使用莫队。另有奇偶优化,即第奇数个块内按 $r$ 从小到大排序,第偶数个块内按 $r$ 从大到小排序,可以减少块间 $r$ 的移动,常数较小。时间复杂度 $O(n\sqrt q)$,提交记录不带奇偶排序的

ABC405G Range Shuffle Query

求区间 $[l,r]$ 内小于 $x$ 的数的多重集排列 $\frac {(\sum_{i<x} t_i)!}{\prod_{i<x} t_i!}$,其中 $t_i$ 为 $i$ 在该区间内出现次数。直接离线下来使用莫队,考虑如何处理修改。可以直接使用线段树或树状数组维护两个前缀内容,时间复杂度 $O(n\sqrt q\log n)$,难以通过。考虑换用修改 $O(1)$ 查询 $O(\sqrt n)$ 的值域分块,这样总复杂度降为 $O(n\sqrt q+q\sqrt n)$,可以通过,提交记录。因此有时可以用值域分块平衡来降低莫队复杂度。

带修莫队:P1903 数颜色 / 维护队列

维护序列,支持单点修改,求区间不同数的个数。由于带上了修改,普通莫队无法解决。考虑多记一维 $t$ 表示该询问在 $t$ 次修改之后,同样以 $B$ 为块长分块,以 $l$ 所在块、$r$ 所在块、$t$ 依次为关键字排序,通过暴力移动 $(L,R,T)$ 依次回答询问,所有修改均容易做到 $O(1)$。

计算一下移动次数,设 $c,q$ 分别为修改和查询次数,每个 $l,r$ 块内 $T$ 的变化量不超过 $O(c)$,共 $O(\frac{n^2c}{B^2})$;$L$ 的移动次数为 $O(qB+n)$,分别为块内移动和块间移动;$R$ 在 $l,r$ 块内移动 $O(qB)$,块间移动 $O(\frac{n^2}B)$,$l$ 块间移动同样是 $O(\frac {n^2}B)$。因此总次数为 $O(\frac {n^2c}{B^2}+qB+\frac{n^2}B)$。

最优的 $B$ 不知道,事实上 Deepseek 也没求出来。若假设 $c>B$ 则前两项平衡可得 $B=n^{\frac23}c^{\frac13}q^{-\frac13}$,此时复杂度为 $O(n^{\frac23}c^{\frac 13}q^{\frac 23}+n^{\frac 43}c^{-\frac13}q^{\frac 13})$,不超过 $V^{\frac 53}$。然而在 $c=0$ 时会求出 $B=1$ 导致超时,用 $c+1$ 求块长即可通过。事实上由于块间移动比块内移动更容易跑满,使用 $B=n^{\frac23}$ 时复杂度为 $O(mn^{\frac23}+n^{\frac43})$,且前一项跑不满,可以通过且用时较短。

回滚莫队:AT_joisc2014_c 歴史の研究

求区间 $it_i$ 的最大值,其中 $t_i$ 为 $i$ 在该区间内出现次数。注意到若所有 $t$ 只增不减,则容易维护当前答案,只需要在增加时尝试更新即可。然而莫队区间收缩时会使得 $t_i$ 变小,难以维护答案,需要使用回滚莫队。

具体地,若询问在某块内则暴力计算答案。将剩余询问放到 $l$ 所在块上,将同块询问按 $r$ 排序后统一处理。同样维护 $L,R$,初始时 $R$ 为 $l$ 所在块右端点,$L=R+1$。之后每到一个询问先暴力将 $R$ 向右拓展,由于已排序,$R$ 单调不降,然后记录目前答案 $X$ 以供回滚。再将 $L$ 向左拓展并记录答案,之后将 $L$ 回滚到初始状态,并把目前答案回滚为 $X$ 即可。这样每个块内 $R$ 移动 $O(n)$,每个询问 $L$ 移动 $O(B)$,复杂度也是 $O(qB+\frac{n^2}B)$,最优为 $O(n\sqrt q)$。提交记录

莫队二次离线:P5047 Yuno loves sqrt technology II

求区间逆序对数,可以离线。先按普通莫队的方式排序,然而区间变化时需要求某区间内大于 / 小于一个数的个数,难以做到较低复杂度,需要优化。考虑把区间个数差分成两个前缀的差,再设 $f(x,y),g(x,y)$ 分别表示 $i\in[1,y]$ 中 $a_i>a_x$ 和 $a_i<a_x$ 的个数,则有以下贡献:

  • $[L,R]$ 变为 $[L-1,R]$:$g(L-1,R)-g(L-1,L-2)$。
  • $[L,R]$ 变为 $[L,R+1]$:$f(R+1,R)-f(R+1,L-1)$。
  • $[L,R]$ 变为 $[L+1,R]$:$-g(L,R)+g(L,L-1)$。
  • $[L,R]$ 变为 $[L,R-1]$:$-f(R,R-1)+f(R,L-1)$。

可以把所有 $f,g$ 的询问再次离线到 $y$ 上,然后依次枚举 $y$,询问时查询值域上的前缀和即可。由于查询次数为莫队移动次数 $O(n\sqrt q)$,修改次数只有 $n$,因此离散化后使用修改 $O(\sqrt n)$ 查询 $O(1)$ 的值域分块即可做到 $O(n\log n+n\sqrt n+n\sqrt q)$ 的时间复杂度。

这里如果直接存下所有的询问,则空间复杂度为常数不小的 $O(n\sqrt q)$,考虑优化。首先注意到有许多形如 $f(i,i-1),g(i,i-1)$ 的重复询问,可以先预处理出这 $O(n)$ 个值。之后发现每次区间变化剩余贡献的 $y$ 相同,且 $x$ 是一段连续区间,因此只记录区间左右端点即可,这样就做到了 $O(n+m)$ 的空间复杂度,提交记录

二维莫队:BZOJ2639 矩形计算

求矩形 $\sum t_i^2$,其中 $t_i$ 为 $i$ 在该矩形内出现次数。所求很像莫队能求的东西,因此把询问全部离线下来,依次按三维所在的块和第四维排序,每次暴力修改当前矩形到目标矩形,这时每移动一次就有 $O(n)$ 的时间开销,实现方式与普通莫队类似。(这里及以下提到的维度指询问的参数)

计算一下时间复杂度,对于 $i\in[1,3]$,第 $i$ 维指针的移动次数为 $O(qB+n\times (\frac nB)^{i-1}$),分别为当前维块内和上一维换块时的移动次数,第四维移动次数就只有 $O(\frac{n^4}{B^3})$。注意到只有 $O(qB+\frac{n^4}{B^3})$ 在瓶颈上,因此以 $B=nq^{-\frac14}$ 平衡得到最优复杂度为 $O(n^2q^{\frac34}+q\log q)$。

当然每一维还可以依赖上一维进行奇偶优化,可以减小常数。另外不是很懂四个参数的优先级,然而经过尝试发现怎么排都行,事实上复杂度分析也不依赖优先级顺序。经过测试,$lx,ly,ry,rx$ 的顺序在本题表现最好,提交记录

树上莫队:P4074 糖果公园

树上点有点权,单点修改,求路径 $\sum v_i(\sum_{j=1}^{t_i}w_j)$,其中 $v,w$ 给出,$t_i$ 为 $i$ 在该路径上出现次数。所求很像莫队能求的东西,但是莫队在序列上才好做,因此需要把树压成序列,同时要求树上路径可以用区间表示。

考虑用 DFS 括号序,即每个点在进入和回溯时分别记录 $in$ 和 $out$。为了表示路径,这里认为 $in_i,out_i$ 均在区间内时 $i$ 点无贡献,这也可以 $O(1)$ 修改。表示 $in_x<in_y$ 的 $x,y$ 间路径时,先找出两点的 LCA $z$。若 $z=x$ 则 $[in_x,in_y]$ 即所求;否则 $[out_x,in_y]$ 再加上 $z$ 点即所求,在询问上记录附加点即可。

这样就得到了序列长度 $2n$,询问数不变的带修莫队,使用前述做法即可解决,时间复杂度 $O(mn^{\frac 23}+n^{\frac 43})$,实现上有一些细节,提交记录。另外 OIWiki 给出了不压成序列的树上莫队算法,感觉困难,且括号序应该够用了,所以没学。

HT-65-NOI-T2 题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-06-24 21:16:11

题意

设一棵树的权值为 $\max_{x}(\sum_i \left|w_i-x\right|)$,其中 $w_i$ 为所有边权,$x$ 取任意实数。给定 $n$ 个点 $m$ 条边的无向图,求其最大权值生成树。$n\le 2\times {10}^5,m\le 5\times {10}^5$。

题解

显然给定 $w$ 后取其中位数为 $x$ 一定最优。考虑枚举边权作为中位数 $x$,以其为分界点,认为 $w\le x$ 的边为白边,权值为 $x-w$;其余为黑边,权值为 $w-x$。此时若 $n$ 为奇数,则两种边各选 $\frac{n-1}2$ 条即可;若 $n$ 为偶数,考虑两种边各选 $\lfloor \frac{n-1}2\rfloor$ 条,即少选一条边,形成两个连通块。由于边权均非负,一定不会超过答案;而枚举到最终答案中位数时,会得到对应生成树去掉中位数边的两个连通块,而该边权值为 $0$,因此一定可以求出答案。

此时需要解决两种边分别选择 $c=\lfloor\frac{n-1}2\rfloor$ 条的最大生成森林,官解给了一种每次增加一条白边的做法,笔者不会证也没写。事实上目前题意即为 [国家集训队] Tree I,可以使用 wqs 二分求解。具体地,设 $f_i$ 表示 $i$ 条白边的答案,则 $(i,f_i)$ 形成了一个上凸包。证明不太会,感性理解可以从没有白边开始,每次增加一条白边,答案能增多的值不多于上次。从没有黑边开始同理,这两种各能得到四分之一个凸包,因此整体是上凸的。

考虑用斜率为 $k$ 的直线切这个凸包,切到的点 $t$ 随 $k$ 增大而减小。确定 $k$ 后要最大化截距 $b=f_i-ki$,可以将 $-ki$ 的贡献放到每条白边上,即将白边权值改为 $x-w-k$,然后用 Kruskal 求最大生成森林,从而得到最大的 $b$ 和对应的白边条数 $t$。这里可在 $b$ 最大前提下要求白边数量 $t$ 尽可能少,然后二分出 $t\le c$ 的最大 $k$,该 $k$ 即可切到 $(f_c,c)$ 点,再跑一遍后求 $f_c=b+kc$ 即为答案。对所有中位数取最大值即可,注意要判掉无解情况,时间复杂度 $O(m^2\log V\lpha(n))$,可以得到 $50$ 分。

#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+10;
const int P=1e9+1e7;
const ll inf=1e18+1e17;
int n,m,ct,c,a[N],f[N],s[N]; ll res,ans=-inf;
struct edg{int u,v,w,f;}e[N],E[N];
bool cmp(edg ta,edg tb)
{
	if(ta.w==tb.w) return ta.f<tb.f;
	return ta.w>tb.w;
}
int finds(int x) {return f[x]==x?x:f[x]=finds(f[x]);}
bool merg(int x,int y)
{
	x=finds(x),y=finds(y);
	if(x==y) return false;
	s[y]+=s[x],f[x]=y; return true;
}
int chk(int x,int k)
{
	for(int i=1;i<=m;i++) e[i]=E[i],e[i].f=(e[i].w<=x),e[i].w=abs(e[i].w-x)-e[i].f*k;
	sort(e+1,e+1+m,cmp),res=0; int C=0,cx=0;
	for(int i=1;i<=n;i++) f[i]=i,s[i]=1;
	for(int i=1;i<=m;i++)
	{
		if(merg(e[i].u,e[i].v)) C++,cx+=e[i].f,res+=e[i].w;
		if(C==c*2) break;
	}
	return cx;
}
ll check(int x)
{
	int l=-P,r=P,rk=P+1;
	while(l<=r)
	{
		int mid=((l+r)>>1),t=chk(x,mid);
		if(t<=c) rk=mid,r=mid-1;
		else l=mid+1;
	}
	if(rk==P+1||chk(x,rk-1)<c) return -inf;
	chk(x,rk); return res+1ll*c*rk;
}
int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m,c=((n-1)>>1);
	for(int i=1;i<=m;i++) cin>>E[i].u>>E[i].v>>E[i].w,a[i]=E[i].w;
	sort(a+1,a+1+m),ct=unique(a+1,a+1+m)-a-1;
	for(int i=1;i<=ct;i++) ans=max(ans,check(a[i]));
	cout<<ans;
	return 0;
}

观察上述代码,注意到同时给所有边加上一个值 $x$ 不会改变最终树的形态,即求出的白边条数 $t$ 不变。因此白边边权变为 $2x-k-w$,黑边边权变为 $w$。此时 chk 函数的结果只与 $X=2x-k$ 有关,根据上面的凸性可以说明此时 $t$ 随 $X$ 增大而增大,因此可以直接二分 $X$ 求解。

此时要求的问题如下:原图中每条边产生白边 $(u,v,X-w)$ 和黑边 $(u,v,w)$,求 $w\le x$ 的白边和 $w>x$ 的黑边形成的 $2c$ 条边的最大生成森林。考虑直接在 $2m$ 条边中用 Kruskal 求解,并证明这样做是对的。首先若存在黑边 $w_1$ 和白边 $X-w_2$,且 $w_1<w_2$,显然改为黑边 $w_2$ 和 白边 $X-w_1$ 更优,因此跑出的结果一定是 $w$ 上某个前缀为白边,之后为黑边。

此时显然存在一个 $x$ 满足该前缀 $w\le x$ 且之后 $w>x$,因此这样做是对的。最终答案为 $\sum\left|x-w\right|$,在黑白边均为 $c$ 条时即为 $\sum_{i>x} w_i-\sum_{i\le x}w_i$,即跑出的最大生成森林权值和减去 $cX$,这样就做完了。由于按 $X-w$ 排序只需要将 $w$ 有序的序列翻转,不需要每次 chk 都排序,时间复杂度为 $O(m\log V\lpha(n))$。

#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e5+10;
const int P=1e9+1e7;
const ll inf=1e18+1e17;
int n,m,k,c,a[N],f[N],s[N],C,cx; ll res,ans=-inf;
struct edg{int u,v,w;}e[N],E[N];
bool cmp(edg ta,edg tb) {return ta.w>tb.w;}
int finds(int x) {return f[x]==x?x:f[x]=finds(f[x]);}
bool merg(int x,int y)
{
	x=finds(x),y=finds(y);
	if(x==y) return false;
	s[y]+=s[x],f[x]=y; return true;
}
void add(edg te,bool f)
{
	if(C==c*2) return;
	if(merg(te.u,te.v)) C++,cx+=f,res+=te.w;
}
void chk(ll X)
{
	for(int i=1;i<=m;i++) e[i]=E[m-i+1],e[i].w=X-e[i].w;
	res=0,C=0,cx=0; int pa=1,pb=1;
	for(int i=1;i<=n;i++) f[i]=i,s[i]=1;
	while(pa<=m&&pb<=m)
	{
		if(e[pa].w>E[pb].w) add(e[pa],1),pa++;
		else add(E[pb],0),pb++;
	}
	while(pa<=m) add(e[pa],1),pa++;
	while(pb<=m) add(E[pb],0),pb++;
}
int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m,c=((n-1)>>1);
	for(int i=1;i<=m;i++) cin>>E[i].u>>E[i].v>>E[i].w;
	sort(E+1,E+1+m,cmp);
	ll l=-P,r=2*P,rk=-P-1;
	while(l<=r)
	{
		ll mid=((l+r)>>1); chk(mid);
		if(cx<=c) rk=mid,l=mid+1;
		else r=mid-1;
	}
	chk(rk),cout<<res-c*rk;
	return 0;
}

【学习记录】数学

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-07-02 23:30:48

数学啥都不会,最近根据三轮省集 Day6 课件写了几个板子,证明也没咋看。因此本文不包含任何证明,只是记录一下做法方便日后复习。

暂时先写这么多,之后可能会补充,之前的几篇记录也一样。

线性预处理逆元

求 $[1,n]$ 中所有数对 $p$ 取模的逆元,可以递推求解。具体地,设 $p=ik+r,0\le r <i$,即 $p$ 和 $i$ 的带余除法运算。因此有 $ik=-r,\frac 1i=-\frac kr$,即 $inv_i=(p-\lfloor\frac pi\rfloor)inv_{p\bmod i} \bmod p$,代码

求 $n$ 个数 $a_i$ 对 $p$ 取模的逆元,可以类似阶乘预处理出 $s_i=\prod_{j=1}^i a_j$,并求出 $s_n$ 的逆元,再倒着推出所有 $s_i$ 的逆元 $s'i$。这样 $a_i$ 的逆元即为 $s'_i s{i-1}\bmod p$,代码。事实上上个问题也能这么做。

扩展欧几里得算法(Exgcd):P5656

给定 $a,b,c$,求解 $ax+by=c$ 的整数解 $(x,y)$。根据裴蜀定理,当且仅当 $\gcd(a,b)\mid c$ 时有解。因此先求解 $ax+by=\gcd(a,b)$,根据辗转相除法有 $\gcd(a,b)=\gcd(b,a\bmod b),b\ne 0$,因此列出另一个式子 $bx'+(a\bmod b)y'=ax+by$。将 $a\bmod b$ 写成 $a-\lfloor\frac ab\rfloor b$,合并 $a,b$ 同类项得到 $ay'+b(x'-\lfloor\frac ab\rfloor y')=ax+by$,据此可以递归求出 $x',y'$ 再反推出 $x,y$,在 $b=0$ 时返回 $x=1,y=0$,即可得到一组可行解 $x,y$。

设 $\gcd(a,b)=g$,此时有 $X=\frac {cx}g,Y=\frac{cy}g$ 为满足题意的一组解。有时会在一些限制下求 $X,Y$ 的最值,只需要知道所有解均满足 $X'=X+\frac{kb}g,Y'=Y-\frac{ka}g$ 即可,容易求最小正整数解之类的最值,时间复杂度 $O(\log V)$,代码

中国剩余定理(CRT):P1495

给出 $n$ 个同余方程 $x\equiv b_i\pmod {a_i}$,$a_i$ 两两互质,求满足所有方程的最小非负整数 $x$。考虑在不影响其他限制的前提下满足第 $i$ 个限制。具体地,设 $M=\prod_{i=1}^n a_i,c_i=\frac M{a_i}$,即 $c_i$ 为除 $i$ 外的所有模数之积。之后求出 $c_i$ 在模 $a_i$ 意义下的逆元 $c_i^{-1}$,最后求出 $r=\sum_{i=1}^n c_ic_i^{-1}b_i$ 即为可行解,对 $M$ 取模可得最小解。

这里可以感性理解,每一项由于有 $c_i$ 作为系数,不会对其他方程造成影响;而在模 $a_i$ 意义下为 $b_i$,满足了该方程的限制。由于用到了逆元,要求模数两两互质,求逆元使用 Exgcd 即可,时间复杂度 $O(n\log V)$,代码。据说拉格朗日差值也是类似思想。

扩展中国剩余定理(ExCRT):P4777

题意同上,然而不再保证模数互质。考虑直接暴力合并两个方程,可将原式化为 $x-k_ia_i=b_i,x=k_ia_i+b_i$。因此若有 $A,B$ 和 $a,b$ 两个方程,则有 $AK+B=ak+b$,即 $ak-AK=B-b$,其中只有 $k,K$ 未知,可以直接代入 $a,A,B-b$ 用 Exgcd 求出 $k,K$ 的解。之后求出 $b'=b+ka,a'=\frac{aA}g$,$b'$ 对 $a'$ 取模后得到的 $a',b'$ 方程即与上面两个方程等价。

每次合并两个方程,直到只剩一个为止,最终的 $b$ 即为最小非负解。时间复杂度 $O(n\log V)$,代码。所以其实 ExCRT 和 CRT 完全没啥关系,泛用性高的同时可能还容易一些。

卢卡斯定理(Lucas):P3807

给出 $n,m,p$,求 ${n+m\choose n}\bmod p$,$p$ 为质数。卢卡斯定理即 ${n\choose m}\bmod p={n\bmod p\choose m\bmod p}\times {{\lfloor\frac np\rfloor}\choose {\lfloor \frac mp \rfloor}}$,还有一种用 $p$ 进制的写法,两种是等价的。因此求组合数时可以不断递归,直到 $n,m$ 均小于 $p$ 时再暴力求解。这里若预处理 $p$ 以内的阶乘及其逆元,可以 $O(1)$ 计算。时间复杂度 $O(p+\log_pV)$,代码

扩展卢卡斯定理(ExLucas):P4720

题意同上,然而不再保证模数 $P$ 为质数。考虑把组合数拆成阶乘形式 $\frac{n!}{m!(n-m)!}$,然而模数不为质数时不一定有逆元。因此将模数 $P$ 质因数分解为若干 $p^k$,求出这些 ${n\choose m}\bmod p^k$ 的值,再用 ExCRT 合并出答案。

考虑如何求该值,先把所有 $p$ 全拿出来,即变为 $\frac{\frac {n!}{p^x}}{\frac{m!}{p^y}\times \frac{(n-m)!}{p^z}}\times p^{x-y-z}$。现在需要快速求 $n!$ 中除掉所有 $p$ 因子后对 $p^k$ 取模的结果,以及除去的 $p$ 因子个数,分别设这两个值为 $f(n),g(n)$。显然有 $g(n)=g(\lfloor\frac np\rfloor)+\lfloor\frac np\rfloor$,以及 $f(n)=f(\lfloor\frac np\rfloor)+\lfloor\frac np\rfloor s_{p^k}+s_{n\bmod p}$,其中 $s_i$ 表示 $[1,i]$ 中不为 $p$ 倍数的所有数乘积,可以 $O(p^k)$ 预处理出来。含义即先将 $p$ 的倍数取出并除以 $p$,在 $f(n)$ 计算时还用到了模 $p^k$ 的循环节性质。

这样答案即为 $\frac{f(n)}{f(m)f(n-m)}\times p^{g(n)-g(m)-g(n-m)}\bmod p^k$,由于 $f$ 值中不含 $p$ 因子,一定与 $p^k$ 互质,可以直接用 Exgcd 计算逆元。总时间复杂度可以分析到 $O(P\log P)$,代码。所以其实 ExLucas 和 Lucas 基本没啥关系,泛用性高的同时可能还容易一些。

大步小步算法(BSGS):P3846

给定质数 $p$ 和 $b,n$,求最小非负整数 $l$ 使得 $b^l\equiv n\pmod p$。显然答案不会超过 $p$,因为 $p$ 次后一定会出现循环节。考虑设 $B=\sqrt p,l=kB-t,t<B$,有 $b^{kB-t}\equiv n\pmod p$。由于 $p$ 为质数,一定存在逆元,可以直接除过去得到 $b^{kB}\equiv nb^t\pmod p$。这时两边都只有 $O(\sqrt p)$ 种取值,枚举出来找到相等的最小 $kB-t=l$ 即可。时间复杂度为 $O(\sqrt p)$ 或 $O(\sqrt p\log p)$,代码

扩展大步小步算法(ExBSGS):P4195

题意同上,然而不再保证 $p$ 为质数。由于 $b,p$ 不一定互质,可能出现没有逆元的情况。考虑去掉 $b,p$ 的公因子,具体地,先改写成 $b^l-tp=n$,即 $b\times b^{l-1}-pt=n$,这时求出 $d=\gcd(b,p)$,若 $d\nmid n$ 则无解,否则可将 $b,p,n$ 同除 $d$。之后若 $gcd(b,p)$ 仍不为 $1$ 则重复此操作,直到 $b,p$ 互质。

这时得到的式子转化回去为 $Kb^{l-k}\equiv n\pmod p$,其中 $b,p$ 互质,$K$ 为 $k$ 个 $b$ 消掉公因子后剩余部分之积对最终 $p$ 取模的结果。此时就可以直接使用普通 BSGS 解决了,求出答案加上 $k$ 即为最终答案。注意要特判答案不超过 $k$ 的情况,只需在 $K=n$ 时确定目前 $k$ 为答案即可。时间复杂度为 $O(\log p+\sqrt p)$,代码。所以 BSGS 的扩展是转化为能解决的有逆元情况,再套用普通 BSGS 求解的,比之前的两组算法关系密切得多。

求欧拉函数

若要预处理 $[1,n]$ 内的欧拉函数,可以使用线性筛法,令质数 $p$ 的 $\ arphi(p)=p-1$,在筛时若 $p_j\mid i$,则令 $\ arphi(ip_j)=\ arphi(i)\times p_j$,否则令 $\ arphi(ip_j)=\ arphi(i)\times \ arphi(p_j)=\ arphi(i)\times(p_j-1)$,这里基于每个质因子 $p$ 都会给欧拉函数值乘上 $\frac{p-1}p$。代码:

phi[1]=1;
for(int i=2;i<=P;i++)
{
	if(!f[i]) p[++ct]=i,phi[i]=i-1;
	for(int j=1;j<=ct&&1ll*i*p[j]<=P;j++)
	{
		f[i*p[j]]=1;
		if(i%p[j]==0)
		{
			phi[i*p[j]]=phi[i]*p[j];
			break;
		}
		phi[i*p[j]]=phi[i]*(p[j]-1);
	}
}

若要求单个数的欧拉函数值,则可以直接枚举其所有质因子,并按照上面所说的 $\frac{p-1}p$ 计算出答案。代码见下一题的提交记录。

扩展欧拉定理:P5091

求 $a^b\bmod m$,其中 $m\le 10^{8},a\le 10^9,b\le 10^{2\times 10^7}$。扩展欧拉定理即为:

$$a^b\equiv\left\{\begin{matrix}a^b&,b<\ arphi(m)\^{b\bmod\ arphi(m)+\ arphi(m)}&,b\ge\ arphi(m)\end{matrix}\right.\pmod m$$,

当然 $\gcd(a,m)=1$ 时有欧拉定理 $a^{\ arphi(m)}=1,a^b\equiv a^{b\bmod \ arphi(m)}\pmod m$。

因此类似快读读入 $b$ 的每一位,过程中一直对 $\ arphi(m)$ 取模即可。时间复杂度为 $O(\sqrt m+\lg(b)+\log m)$,分别为求欧拉函数,读入和快速幂的复杂度,代码

拉格朗日插值:P4781

给出 $n$ 个点 $(x_i,y_i)$,保证 $x_i$ 互不相同,求一个 $(n-1)$ 次多项式使得 $\forall i,f(x_i)=y_i$,$n\le 2000$。考虑对每个点构造一个多项式 $g_i(x)$,使得 $g(x_i)=y_i,\forall j\ne i,g(x_j)=0$,则 $\sum g_i$ 即为合法的 $f$。一种合法构造为 $g_i(x)=y_i\cdot\prod_{j\ne i} \frac{x-x_j}{x_i-x_j}$,本题直接带入计算即可。若需要求出多项式 $f(x)$ 的系数,可以先计算出 $a_i=\frac{y_i}{\prod_{j\ne i}x_i-x_j}$,再预处理出多项式 $t(x)=\prod x-x_i$ 的系数,每次先求出 $g(x)=\frac{t(x)}{x-x_i}$,再将 $a_i\cdot g(x)$ 加给 $f(x)$ 即可。时间复杂度 $O(n^2)$,提交记录。更低复杂度需要多项式科技,不学。

莫比乌斯反演

定义 $i$ 存在平方因子时 $\mu(i)=0$,否则若其质因子个数为 $k$,$\mu(i)=(-1)^k$。

莫比乌斯函数 $\mu$ 可线性筛求出,有 $\mu(1)=1,\mu(p)=-1$。否则有 $x=i\cdot y$,其中 $y$ 为 $x$ 最小质因子,则若 $y\mid i$,$\mu(x)=0$,否则 $\mu(x)=-\mu(i)$。

定义狄利克雷卷积运算 $\st$ 为 $h=f\st g$ 时 $h(x)=\sum_{d\mid x} f(d)g(\frac xd)$。

定义数论函数 $id(x)=x,1(x)=1,\ arepsilon(x)=[x=1]$。

有性质 $\sum_{d\mid n}\mu(d)=[n=1]=\ arepsilon(n)$,即 $\mu\st1=\ arepsilon$。

还有性质 $\sum_{d\mid n}\ arphi(d)=n$,即 $\ arphi \st1=id$。

上式两边卷上 $\mu$ 得到 $\ arphi\st\ arepsilon=id\st\mu$,展开得到 $\ arphi(n)=\sum_{d\mid n}d\cdot\mu(\frac nd)$。

P4450 双亲数

$T\le 5\times 10^4$ 次询问,每次给定 $A,B,d\le 5\times 10^4$,求 $\sum_{i=1}^A\sum_{j=1}^B [\gcd(i,j)=d]$。先将 $i,j$ 均除掉 $d$,得到 $\sum_{i=1}^{\lfloor\frac Ad\rfloor}\sum_{j=1}^{\lfloor\frac Bd\rfloor}[\gcd(i,j)=1]$,将其用性质展开得到 $\sum_{i=1}^{\lfloor\frac Ad\rfloor}\sum_{j=1}^{\lfloor\frac Bd\rfloor}\sum_{k\mid\gcd(i,j)}\mu(k)$。交换求和号,将 $k$ 放在最前面,得到 $\sum_{k=1}^{\lfloor\frac{\min(A,B)}d\rfloor}\sum_{i=1,k\mid i}^{\lfloor\frac Ad\rfloor}\sum_{j=1,k\mid j}^{\lfloor\frac Bd\rfloor} \mu(k)$。该式的值显然为 $\sum_{k=1}^{\lfloor\frac{\min(A,B)}d\rfloor}\mu(k)\lfloor\frac A {dk}\rfloor\lfloor\frac B {dk}\rfloor$。

线性筛出所有 $\mu $ 的值,本题已经可以做到单次查询线性。然而多次询问时无法通过。考虑对后面的部分整除分块,则两个除式各有 $O(\sqrt V)$ 种取值,两式均不变的连续段数量也是 $O(\sqrt V)$ 级别的。因此对 $\mu$ 预处理前缀和即可做到 $O(V+T\sqrt V)$ 的复杂度,提交记录

P2257 YY的GCD

$T\le 10^4$ 次询问,每次给定 $n,m\le10^7$,求 $i\in[1,n],j\in[1,m]$ 中有多少对 $(i,j)$ 满足 $\gcd(i,j)$ 为质数,设质数集合为 $P$。直接列出式子 $\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)\in P]$,并改为先枚举质数为 $g$,得到 $\sum_{g=2,g\in P}^{\min(n,m)}\sum_{x=1}^n\sum_{y=1}^m[\gcd(x,y)=g]$,然后用上题的过程拆开得到 $\sum_{g=2,g\in P}^{\min(n,m)}\sum_{k=1}^{\lfloor\frac{\min(A,B)}g\rfloor}\mu(k)\lfloor\frac A {gk}\rfloor\lfloor\frac B {gk}\rfloor$。

令 $T=gk$,则原式变为 $\sum_{T=2}^{\min(n,m)}\lfloor\frac AT\rfloor\lfloor\frac BT\rfloor \sum_{g\mid T,g\in P}\mu(\frac Tg)$,需要求出 $f(T)=\sum_{g\mid T,g\in P}\mu(\frac Tg)$。考虑在线性筛过程中预处理,有 $f(1)=0,f(p)=1$。否则有 $x=iy$,其中 $y$ 为 $x$ 的最小质因子。若 $y\mid i$ 则 $g\ne y$ 时 $\frac xg$ 包含 $y^2$ 因子,一定没有贡献,因此只有 $g=y$ 有贡献 $f(x)=\mu(i)$;否则 $f(x)=\sum_{g\mid T,g\in P}\mu(\frac Tg)+\mu(i)=\sum_{g\mid i}\mu(\frac {iy}g)+\mu(i)=-f(i)+\mu(i)$。之后对 $f$ 求前缀和并整除分块求解即可,时间复杂度 $O(V+T\sqrt V)$,提交记录

P2398 GCD SUM

给定 $n\le 10^7$,求 $\sum_{i=1}^n\sum_{j=1}^n \gcd(i,j)$。直接拆并转化成 $\sum_{g=1}^n g\cdot\sum_{k=1}^{\lfloor\frac ng\rfloor}\mu(k)(\lfloor\frac n {gk}\rfloor)^2$,同样令 $T=gk$ 得到 $\sum_{T=1}^n(\lfloor\frac n {T}\rfloor)^2 \sum_{g\mid T}g\cdot\mu(\frac Tg)$,然后试图爆推线性筛式子失败了。事实上上面有性质表明 $\sum_{g\mid T}g\cdot\mu(\frac Tg)=\ arphi(T)$,因此线性筛欧拉函数即可做到 $O(n)$ 和多组 $O(n+T\sqrt n)$ 的复杂度,提交记录

狄利克雷前缀和:P5495

用于解决求 $b_i=\sum_{j\mid i}a_j$ 或 $c_i=\sum_{i\mid j}a_j$ 的问题及其逆问题,时间复杂度 $O(n\ln \ln n)$。该问题的暴力做法为枚举每个数的倍数,时间复杂度 $O(n\ln n)$。

考虑以每种质因子为一维,此时每个下标是高维内一个点,$i$ 的因数是每一维均不大于其的点,倍数是每一维均不小于其的点。因此在该意义下对 $a$ 数组做高维前缀和即可得到 $b$,做高维后缀和即可得到 $c$。具体实现仍然在一维数组内,枚举每个质因数 $p$,并按某种顺序枚举所有 $ip\le n$ 更新即可。注意前缀和正序,后缀和逆序枚举,逆问题差分时与原问题顺序相反。时间复杂度分析方式同埃氏筛,我都不会,是 $O(n\ln\ln n)$ 的,提交记录

U540870 课后习题 2

给定长为 $n$ 的序列 $a$,求序列 $b$ 使得 $b_i=a_i+\sum_{j\mid i,j<i} b_j$。$n\le 2\times 10^7$。注意到 $j\mid i,j<i$ 的 $j$ 一定不超过 $\lfloor\frac i2\rfloor$,因此通过值域倍增的方式来保证计算 $b_i$ 时所需 $b_j$ 的值均已确定。

具体地,设 $m$ 表示目前 $[1,m]$ 内的 $b_i$ 均处理好了。每次取 $m'=\min(2m,n)$,然后处理 $[m+1,m']$ 内的所有 $b$。此时先将 $[1,m]$ 内的 $b$ 复制一份到 $t$ 中,之后在 $t$ 上做 $[1,m']$ 的狄利克雷前缀和,得到的 $t_i,i\in[m+1,m']$ 即为 $\sum_{j\mid i,j<i} b_j$,因此有 $b_i=a_i+t_i$,这样就完成了这部分 $b$ 的求解,最后更新 $m=m'$ 即可。

下面分析时间复杂度,大概是 $\sum_{i=0,2^i\le n} O(2^i\ln\ln(2^i))$,在 $i$ 最大时的取值大概为 $O(n\ln\ln n)$,且 $i$ 较小的情况下复杂度总和不超过该值,这是由于 $\sum_{j=0}^{i-1} 2^j=2^i-1$。因此总时间复杂度仍是 $O(n\ln\ln n)$ 的,提交记录

25.07-MX 模拟赛题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-07-04 19:59:48

风物长宜放眼量,心胸要开阔。

D1T1 琥峪枫

题意

交互。有一棵高度为 $h$ 的完全二叉树和一个长为 $n=2^h-1$ 的排列 $p$,点有点权 $f_i$。可询问 $(u,d)$,得到 $\sum_{dis(p_u,v)=d}f_v$,其中 $dis(i,j)$ 表示 $i,j$ 两点间路径边数,求 $\sum f_i$。多组数据,$\sum n\le 10^6,1\le f_i\le 10^9$,满分要求 $q\le 2n+3$,且同一个 $u$ 询问不超过 $4$ 次。

题解

设 $A(u,d)$ 表示询问 $(u,d)$ 的答案。考虑求出 $\sum A(i,1)$,其中根节点贡献两次,叶子节点贡献一次,其余节点均贡献三次,只需再求出根节点权值和叶子节点权值和即可求答案。考虑找到根节点 $r$,注意到由于权值为正,只有根节点的 $A(r,h)$ 为 $0$,同理只有前两层 $A(i,h+1)$ 为 $0$。因此只需询问一轮即可得到前两层的三个点。

之后对这三个点分别询问 $A(i,h)$,从而确定根节点 $r$ 和另外两个第二层节点 $x,y$。同时叶子节点之和即 $A(x,h)+A(y,h)$,正好能用上。至于根节点权值,可以使用 $\frac{A(x,1)+A(y,1)-A(r,2)}2$ 求出,其中前两项已经在开头求过了。

分析一下操作次数,$A(i,1),A(i,h+1)$ 共 $2n$ 次,$A(i,h)$ 三次,加上 $A(rt,2)$ 共 $(2n+4)$ 次。然而注意到 $A(i,h+1)$ 只用于筛选出三个点,因此只求 $(n-1)$ 次就行,总次数降到 $2n+3$,可以通过。赛后好像被爆标到 $2n-3$ 了,恐怖。

D1T2 篱莘龙

题意

在序列中选元素,能同时选 $i,j$ 当且仅当 $a_i<b_j$。给出长为 $n$ 的序列,对每个前缀求其中最多能选的元素个数。$n\le 10^6$,$a_i,b_i$ 两两不同。

题解

注意到若 $a_i>b_i$ 且 $a_j>b_j$,则一定有 $a_i>b_j$ 或 $a_j>b_i$,因此 $a>b$ 的最多选一个。若只选 $a<b$ 的,则要求 $\max a<\min b$,可以枚举分界点 $p$,统计 $a\le p<b$ 的个数求解。把这个扔上线段树可以做到 $O(n\log n)$。

再考虑选一个 $A>B$ 的 $(A,B)$,以下称这种元素为询问,其余为贡献点,此时要求其余 $a<B$ 且 $b>A$。将其放到 $a,b$ 的坐标系上,则有且仅有 $(B,A)$ 左上角的点能选。注意到询问间若有包含关系则可以删掉,剩余 $B,A$ 一定均单调递增。

此时若新加一个贡献点 $(x,y)$,则 $B>x$ 且 $A<y$ 的询问答案加一。由于 $B,A$ 均单增,贡献到的一定是一段区间,可以以 $B$ 为下标建线段树维护。若新加一个询问 $(B,A)$,先判断是否存在 $B'>B,A'<A$ 将其包含,有则无法加入,再删掉 $B'<B,A'>A$ 的被包含询问即可。

这里求区间可对 $A,B$ 各开一个 set 维护,同时维护增删,删除时线段树赋值 $-\infin$,现在还需求加入时被包含的贡献点数,即已存在的 $x<B,y>A$ 数量。考虑差分思想,用总点数分别减掉 $x>B$ 和 $y<A$ 的点数,再加回两者均满足的点数。然而在坐标系中画图可以发现,若存在两者均满足的点,则一定存在只选贡献点的方案不劣于选该询问。因此可以忽略加回点的操作,这样若答案选择该询问则不受影响,反之也不会导致答案增大,是正确的。

因此二维偏序转化为了两个一维偏序,开两棵树状数组即可维护 $x>B$ 和 $y<A$ 的点数。前面还使用了两棵线段树和两个 set,可以以大常数 $O(n\log n)$ 的时间复杂度通过本题。另外计算加入询问时的初值还有其他巧妙方法,也是在坐标系中分析某块没有点。还有先求出只用 $a<b$ 的答案再分析能否加一的做法,只听了个大概,没有细想。

D2T1 流(谒醨溪

题意

序列 $a$ 需要满足 $l_i\le a_i\le r_i$,还有 $m$ 条 $a_{x_i}\oplus a_{y_i}=z_i$ 的限制,求字典序最小的合法序列。多组数据,$n,m\le 2\times 10^5,\sum n,\sum m\le 4\times 10^5,0\le l_i,r_i,z_i<2^{30}$。

题解

把限制看成边,连通块内的取值互相影响,即确定一个就确定了整个连通块,此时一定最小化最靠前的那个;而连通块间是独立的,可以分开计算。具体地,以最靠前的位置为根,DFS 一遍得到所有点与根的异或值 $d_i$,出现冲突则无解。设根节点值为 $x$,则每个点存在限制 $l_i\le x\oplus d_i\le r_i$,$c$ 个点共 $c$ 条限制。

现在需要求出 $c$ 条限制下的最小合法 $x$,把每个限制拆成两个,这里以 $x\oplus d_i\le r_i$ 为例。可以找出 Trie 树上 $d_i\oplus r_i$ 到根的路径,再枚举两者 LCP,若该位可以满足条件,则该路径相邻的一棵子树均合法,对其打标记即可,另一种限制同理。建出访问过的 $O(c\log V)$ 个点,最后遍历一遍,找到满足所有限制,即打了 $2c$ 个标记的最小 $x$ 作为根节点的值,其他点的值即为 $x\oplus d_i$,若不存在合法 $x$ 则无解。时间复杂度 $O(n\log V)$。

D2T2 芳权多

题意

给出一个长为 $n$ 的字符串,每次修改同时将其所有 "he" 子串改为 "she","his" 子串改为 "her"。$q$ 次询问给出 $k,x$,求原串修改 $k$ 次后的第 $x$ 个字符。多组数据,$T\le 5,n,q\le 2\times 10^5,k,x\le 10^9$。

题解

先将查询按 $k$ 排序,尝试维护操作后的串。注意到 "he" 只会每轮向前生成一个 's',且本身不会消失;而 "hi" 碰到 's' 后会变为 "her",该 's' 可能是原序列中的,也可能是后面的 "he" 生成的,且其改变后自身也可以向前生成 's'。因此比较重要的是 "hi" 变为 "he" 的操作,这里设 $t_i$ 表示 $i,i+1$ 位置的两个字符在第 $t_i$ 轮变成 "he",之后每轮产生一个 's'。若这两个字符不为 "he" 或 "hi",则 $t_i=\infin$。"he" 的 $t_i=0$,"his" 的 $t_i=1$,其余 "hi" 需要后面给出 's',即 $t_i=t_{i+2}+2$。

再按照 "he" 和 "hi" 将串划分成若干段,除第一段外每段都以 "he" 或 "hi" 开头。这样之后每段均形如若干 's' 加上一个串,后面的串总长为 $O(n)$。考虑直接记录下后面的串,并用线段树维护每个段的长度。令每个叶子节点代表一个段,$c_u=1$ 表示该段已经可以产生 's'。每轮先给全局 $c_u=1$ 的加一,再将 $t_{L_i}=T$ 的单点 $c$ 值改为 $1$,并修改 $i$ 的串为 "her"。还要给后一个段单点减一,表示有一个 's' 放到前面凑成了 "his",并变成了前一段内的 'r'。这是 "hi" 且不为 "his" 的修改方式,而其他 $t_i\le 1$,可以在开始前预处理。

这些操作均可使用线段树实现,维护一下区间 $c$ 的和即可。询问时线段树上二分找到所在段,判断一下该字符是否为前缀 's',不是则去记录的段里找字符。另外 "hi" 一定会在 $n$ 轮内被激活,之后 $c$ 轮操作可以直接全局加 $c$,这样操作次数降为 $O(n+q)$,时间复杂度 $O(T(n+q)\log n)$。还有用线段树维护一次函数的做法,感觉也是差不多的。

D2T3 染色

题意

二维平面上有 $n$ 个黑点 $(x_i,y_i)$,其余点为白点。每次操作可任选两个整数 $x,y$,将 $(x,y),(x,y+1),(x+1,y)$ 三个点的颜色取反。要求最后只剩一个黑点,求该黑点坐标,保证有解。$1\le n\le 10^4,-10^{17}\le x_i,y_i\le 10^{17}$。

题解

先考虑值域较小的情况。尝试将点转化到同一条线上,取 $Y \le \min y_i$ 并选择 $y=Y$ 这条横线。观察转化过程,发现点 $(x_i,y_i)$ 会贡献到所有满足 ${y_i-Y\choose t}$ 为奇数的点 $(x_i+t,Y)$。根据 Lucas 定理的结论,该限制等价于二进制下 $t\subseteq (y_i-Y)$。

若将答案 $(x_0,y_0)$ 贡献到直线 $y=Y$ 上,最靠边的贡献点分别满足 $t=0$ 和 $t=y_0-Y$,即横坐标分别为 $x_0,x_0+y_0-Y$。于是将初始点暴力贡献到该横线上,再找到最靠边的黑点横坐标 $L,R$,答案即为 $(L,R-L+Y)$。时间复杂度 $\mathcal O(nV)$。

以上做法告诉我们,找到 $y=Y$ 上最靠边的黑点横坐标 $L,R$ 即可求出答案。由于所求 $L,R$ 分别对应 $t=0$ 和 $t=y_0-Y$,只需求出任意一个黑点横坐标 $X$,即可从高位到低位倍增求出 $L,R$。

具体地,对每个二进制位 $2^k$,若 $(X-2^k,Y)$ 仍为黑点,则 $y_0-Y$ 和当前 $t$ 该位均为 $1$,需要更新 $X\leftarrow X-2^k$,最终得到的值即为 $L$。对 $R$ 的求解是类似的,只需变减为加即可。判断某个点的颜色可以枚举所有初始点计算贡献,单次复杂度 $\mathcal O(n)$,总复杂度 $\mathcal O(n\log V)$。

于是目标变为找到横线上任意一个黑点。类似上题做法,对所有点按 $(x-y)\bmod 3$ 划分等价类。每次操作三个等价类内各取反一个点,三者的黑点数奇偶性均改变。又因为最终状态只有一个黑点,每个状态下都存在黑点数为奇数的等价类。

在该横线上同样划分等价类,找到奇数个黑点的等价类 $c$,再对其不断二分,每次向奇数个黑点的一侧递归,即可找到一个黑点。

二分中需求解的问题为:给定 $l,r,c$,求初始点贡献到横线上后,$[l,r]$ 区间内横坐标模 $3$ 为 $c$ 的黑点个数奇偶性。由于不关心具体个数,可对每个初始点分别求出贡献点数奇偶性。由于贡献点异或只会导致点数减少 $2$,这些奇偶性异或起来即为最终黑点数奇偶性。

于是分别对初始点 $(x_i,y_i)$ 求 $[l,r]$ 内有多少模 $3$ 为 $c$ 的 $X$ 满足 $(X-x_i)\subseteq (y_i-Y)$。对 $t=X-x_i$ 考虑,设 $f_{k,liml,limr,c}$ 表示填了 $2^k$ 及更高位,这些位上满足包含限制,是否仍然等于上下边界,当前值模 $3$ 为 $c$ 的数字个数奇偶性,直接数位 DP 即可,单次复杂度 $\mathcal O(\log V)$。

令 $V=10^{17}$,由于坐标绝对值不超过 $V$,可取 $Y=-V$。此时贡献点在 $[-V,3V]$ 内,答案 $x_0,y_0$ 满足 $x_0\ge -V,x_0+y_0\le 2V$,可推出 $y_0\le 3V$。若贡献到竖线 $x=-V$ 同样可得 $x_0\le 3V,y_0\ge-V$,于是答案坐标在 $[-V,3V]$ 之间,倍增和数位 DP 从 $2^{58}$ 开始即可。

关于复杂度,瓶颈在于二分找任意黑点的 $\mathcal O(n\log^2 V)$,倍增求 $L,R$ 的 $\mathcal O(n\log V)$ 不在瓶颈上。提交记录

D3T1 迷宫

题意

给出一棵树,边有边权 $w_i$。$q$ 次询问给出 $x,y$,求 $x$ 到 $y$ 路径上边权的最长不下降子序列。$n\le 10^5,q\le 3\times10^{6},w_i\le k\le10$。

题解

暴力可以树剖,将路径剖成 $O(\log n)$ 条重链,并用线段树之类的东西硬维护一下,可能需要至少 $O(qk^3\log n)$,难以通过,需要减少段数来消掉这个 $\log n$。然而在 LCA 处断开很不好做,考虑点分治并在分治中心处断开,这样总共要处理的点数降到 $O(n\log n)$,看起来比较能做。

因此先建出点分树,把每个询问挂到点分树上 LCA 处,在以其为分治中心时处理。点分治时只需要 DP 求出中心到各点开头为 $i$ 的最长不上升 / 不下降子序列,之后枚举断点拼起来即可。这里实现有优劣,若枚举开头结尾是 $O(sk^2)$ 的,总时间复杂度为 $O(nk^2\log n+q(k+\log n))$,据说有能消掉一个 $k$ 的做法,没想。

D3T2 排列计数

题意

定义排列 $P$ 中下标 $i$ 是好的当且仅当 $P_i>P_{i+1}$ 且 $P_i$ 为前缀最大值,排列 $P$ 的权值 $f(P)$ 为其冒泡排序每一轮前好的下标数量之和。给出 $m$ 条限制 $p_{x}=y$,求所有满足限制的排列权值之和,取模。$0\le m\le n\le 10^6$。

题解

考虑求给定排列的权值,注意到一轮冒泡排序会将每个前缀最大值移到下一个之前,而实际上会移动的只有好的下标上的数,因此可转化为求总移动次数。考虑计算每个数 $p_i$ 会向后移动多少次,设 $f_j=[p_j\ge p_i]$,则 $p_i$ 每次实际移动会跳过 $f$ 上的一个 $0$ 连续段。再考虑 $i$ 前面元素的影响,显然 $0$ 不会跳到 $p_i$ 之后,$1$ 也不会拆开原来的 $0$ 连续段,因此跳的次数即为其后 $0$ 连续段的个数,答案也是连续段个数之和。

考虑如何统计答案,先转化为计算 $i$ 及之后 "10" 的出现次数,这里要求 $i\le j<n,p_j\ge p_i,p_{j+1}<p_i$,可以直接枚举 $i,p_i=x,j$,计算 $p_j,p_{j+1}$ 的方案数,复杂度 $O(n^3)$。注意到很多东西只与 $x$ 及合法位置 $j$ 的个数有关,因此倒序枚举 $i$,并维护各种 $j$ 的个数,复杂度降为 $O(n^2)$。再注意到位置 $j$ 总是贡献到 $x$ 的一段区间,且 $p_i$ 给定时 $x$ 取值唯一,否则可以任取没有给定的数,也即只有单点和全局查询。因此用树状数组维护单点的合法 $j$ 个数,同时维护全局系数和即可,时间复杂度 $O(n\log n)$。本题关键在于注意到连续段性质,优化细节此处略去。

D3T3 白井黑子

题意

有一棵 $n$ 个点的树,两个数组 $f,a$,$f_i$ 初值为 $i$ 的父亲节点。求该树的任意 DFS 序并存到 $a$ 中,除两个数组外只有 0.75Mib 可用空间。$n\le 10^7$。

题解

注意到需要找到一种顺序遍历整棵树,使用左儿子右兄弟表示法,即维护每个点第一个儿子 $a_i$ 和下一个兄弟 $t_i$。若有这两个辅助数组,可从 $p=1$ 开始遍历,若当前 $a_p=0$ 则说明 $p$ 子树已遍历完,需要记录遍历完的顺序,可以直接记录在空的 $a_p$ 中,之后跳到其下一个兄弟 $t_p$,若无则返回父亲 $f_p$;若 $a_p$ 存在就直接跳到 $a_p$,并将 $a_p$ 清空为 $0$。这样得到的 $a$ 是树的后序遍历,倒过来即可得到一个 DFS 序。

这样需要 $O(n)$ 的额外空间开数组,无法接受。注意到过程中只有每个点的最后一个儿子会跳到父亲,其 $t_i$ 一定为空,同时其余节点遍历时用不到父亲,因此可将两个数组合并,只记录遍历过程中的下一个节点,即可满足空间限制。具体实现时直接用 $f$ 数组作为 $t$,类似链式前向星,枚举每个点 $i$ 和其父亲 $x$,若父亲已有儿子 $a_x$ 则先以其为下一个兄弟,即令 $f_i=a_x$,并将 $x$ 的第一个儿子改为 $a_x$;否则直接令 $a_x=i$,且保留其父亲信息。跑一遍后先用 $a$ 中的排名还原出后序遍历存到 $f$,再翻转整个序列存到 $a$ 即为答案。

总之这种题还是挺巧妙的,思维含量很高,代码也很好写,感觉和 D1T1 是差不多类型的题。

D4T1 弱

题意

在原点有一枚棋子,每次按照 $w_u:w_d:w_l:w_r$ 的概率随机向上下左右中某个方向移动 $1$,共移动 $n$ 次,求经过不同整点个数的方差。方差定义为 $\sum p_i(i-E)^2$,其中 $p_i$ 表示经过 $i$ 个不同点的概率,$E$ 表示个数期望。$n,w\le 100$。

题解

以下设 $S=\sum w$。先推一推方差的式子,得到 $\sum p_ii^2-2p_iiE+E^2=\sum p_ii^2-E^2$,因此只需要求出个数期望和个数平方的期望即可。个数期望容易拆贡献,即对每一步走到新点的概率求和。这里先计算路径数,设 $g_i$ 表示走 $i$ 步后第一次到某个点的路径数,则有 $g_i=S^i-\sum_{j=0}^{i-1}g_j\times A(i-j,0,0)$,其中 $A(i,x,y)$ 表示走 $i$ 步到达 $(x,y)$ 的路径数,该式在第一次到某点时统计或容斥。有 $E=\sum_{i=0}^n \frac{g_i}{s^i}$。

考虑同样把平方的期望拆贡献,则每条路径的贡献为 $\sum_{0\le i\le j\le n}2t_it_j$,其中 $t_i=1$ 表示 $i$ 在路径上,$t_i=0$ 表示不在路径上。因此求出 $C$ 表示所有不同点对均被经过的路径条数和,则 $\sum p_ii^2=\frac {2C}{S^n}+E$,其中 $E$ 即 $i=j$ 产生的贡献。 考虑设 $f(i,x,y)$ 表示所有三元组 $(j,u,v)$ 使得 $j<i$,且 $j$ 步时首次到 $(u,v)$,$i$ 步时首次到 $(u+x,v+y)$ 的路径数总和。 所求即 $C=\sum_{i=0}^n\sum_x\sum_y f(i,x,y)\times S^{n-i}$。

考虑 $f$ 的计算方式,首先赋值 $f(i,x,y)=\sum_{j=0}^{i-1} g_j\times A(i-j,x,y)$,但显然会多算一些东西,先减去多次访问 $(u+x,v+y)$ 的重复贡献,即减去 $\sum_{j=0}^{i-1}f(j,x,y)\times A(i-j,0,0)$。再减去第 $j$ 步到 $(u,v)$ 前到过 $(u+x,v+y)$ 的路径数,即减去 $\sum_{j=0}^{i-1}g_j\times S(i-j,-x,-y)$,其中 $S(i,x,y)$ 表示走 $i$ 步经过 $(x,y)$ 后回到原点方案路径数。然而其中存在 $j$ 步前到过 $(u,v)$ 的路径,然而开始时保证了首次到 $(u,v)$,因此这些并不存在却被减了一次,需要加回 $\sum_{j=0}^{i-1} f(j,x,y)\times S(i-j,-x,-y)$,这样就计算完了。

最后需要解决 $A,S$ 的计算,$A(i,x,y)$ 可以枚举向上的步数 $k$,即可推出四个方向的步数,再用多重集排列算一下方案数,乘上对应的 $w$ 次幂求和即可。而 $S(i,x,y)=\sum_{j=0}^i R(j,x,y)\times A(i-j,-x,-y)$,其中 $R(i,x,y)$ 表示走 $i$ 步首次到 $(x,y)$ 的路径数,这样即在首次经过处统计。有 $R(i,x,y)=A(i,x,y)-\sum_{j=0}^{i-1}R(j,x,y)\times A(i-j,0,0)$,即在首次到 $(x,y)$ 处容斥。最终所有转移均只枚举 $j$ 一个值,且状态数为 $O(n^3)$,总复杂度 $O(n^4)$。

D5T1 最大公约数

题意

给出长为 $n$ 的序列 $a$,每次操作可将相邻两数变为两者 gcd。$q$ 次询问给出区间 $[l,r]$,求对该区间最少操作多少次能把数变为全相同,询问独立。$n,V\le 10^5,q\le3\times 10^5$。

题解

对于询问先求出区间 gcd 为 $g$,显然过程中的所有数一定均为 $g$ 的倍数。设最终剩余数均为 $kg$,则若 $k\ne 1$,区间内一定存在一个数不为 $kg$ 倍数,无法满足,因此最终一定得到若干个 $g$。考虑从左端点开始找到最小的 $p$,使得 $[l,p]$ 的 gcd 为 $g$,将答案加一再更新 $l\leftarrow p+1$。如此直到 $p>r$,此时把 $[l,r]$ 均划分进上一段即可。这样可求出最大段数,用区间长度减一下就是答案。

考虑如何快速求出该段数。$[l,i]$ 的 gcd 形成至多 $\log V$ 个连续段,因此记录三元组 $(l,g,p)$ 表示 $[l,p]$ 的 gcd 为 $g$,且 $p$ 为该段开头。三元组共有 $O(n\log V)$ 个,将其按照 $g$ 分类,同时将询问也离线下来按照区间 gcd 分类。之后枚举 $g$,使用所有三元组建出倍增数组 $f_{i,j}$,表示从 $i$ 开始往后接 $j$ 个连续段的右端点,每个询问倍增跳一下即可。时间复杂度 $O(n\log n\log V+q\log n)$。

D5T2 杏酥桐

题意

维护一棵树,初始只有根节点 $1$。修改会增加一个新点,并将其插入到 $u$ 点的子节点序列,作为其第 $k$ 个儿子。查询时给出 $u,x$,询问对当前树进行 $x$ 次左儿子右兄弟变换后 $u$ 的父亲。询问独立,保证修改合法。多组数据,$T\le 3,q\le 10^6,u\le n,x\le 10^9$。

题解

先只考虑单次变换,此时若 $u$ 为其父亲的第一个儿子则不变,否则父亲变为原父亲的上一个儿子。可以注意到之后每次变换时前者仍不变,后者会变成原父亲 DFS 序的后继,直到后继为 $u$ 自身时不再改变。因此需要实时维护 DFS 序和每个点目前的子节点序列,从而求出某个点在其父亲的子节点序列中的前驱,以及 DFS 序上某个点之后第 $k$ 个点。

实现时可以先记录下所有操作并建出树,在上面跑出 DFS 序,之后倒序确定每个点的位置,方式即对每个点维护目前还没被占的子节点位置,在上面找到对应位置并分配即可。最后正序处理每个询问,在 DFS 序上维护目前已产生的点,即可查询出某点后第 $k$ 个点。以上均可以使用线段树维护区间点数,并使用线段树二分求解。另外查前驱只需要对每个点用 set 维护其目前存在的子节点即可,时间复杂度 $O(Tq\log q)$。

NOI2025 游记

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-07-19 09:06:01

省流:D 类,$384$,铜,会接着冲。

不省流的话,就接着看下去吧。

如果我还能回到某天

拾起了 残存脑海的思念

如玻璃碎片 刺入心底海面

徘徊着 转眼又消失不见

——《光影流年,终有一天。

Day.-10 - Day.-2(7.3-7.11)

坐飞机去的绍兴,然后在鲁迅中学参加梦熊集训。

大手子梦熊提供了 NOI 同款键盘,题目质量也不错,打得还行,就是饭一言难尽。

中间两场 UNR 爆炸了,不管,心胸要开阔。

打完 UNR 那天教练来了,带我们去柯桥古镇吃了个饭,逛到九点才回去。

之后有两个学长分享经验,印象最深的是"打出自己的真实水平",感觉很有道理。

7.11 结束后去酒店住了一晚,逃离了全是蚊子的老旧宿舍。晚上打了好久的塔,好玩。

Day.-1(7.12)

爽睡到快九点,吃了饭去报到。

领到了赠送徽章,交换了不少,比较爽。

下午去 scallion 和黑塔屋玩画猜,吃饭,打曹神给的有用板子,睡觉。

Day.0(7.13)

似乎由于空调温度过低感冒了,晚上还有点打呼,调到了临时宿舍。

开幕式,前面忘了杜子德讲话后面忘了,总之制度好。

下午试机和笔试,喜提挂一分,被 kill 杀了,没背熟导致的。

不管了,心胸要开阔,睡觉了。

偷生为草芥 覆死化土野

随流奔入夜 残阳仍渴血

清唱云不去 弹弦风飒来

草野思云雨 莫去求花开

——《花草野

Day.1(7.14)

比赛日,其实挺慌的,毕竟这种大场馆比赛就没打好过。而且感觉题可能很困难,心里没啥底。但集合时还在终极猎手群里玩画猜,算是调整了下心态。

进场开题。T1 图论,哦状态数只有 $O(m)$,转移分两类,先用前缀和算一下贡献。好像可以前缀优化建图,我建建建。诶怎么建出来有负权,哦拆到不同边上就行了,怎么这么简单,半个小时左右就差不多会了,开写。

写完后一直挂大样例,调试若干分钟后发现犯了唐氏错误,两个小时才调出。然后开 T2,感觉困难,好像只会暴力分啊。再看看 T3,感觉更是困难完了,写完 $8$ 分就扔了。回来给 T2 胡了个复杂度爆炸的区间 DP 求第一问,写了记忆化搜索上去。然后已经没时间了,于是拼了小数据和特殊性质上去,最后在 Pretest 得到 $32$ 分,总分 $100+32+8=140$ 离场。

出场过程中隔壁老哥说他把 T2 第一问一眼秒了,T3 也还有 $8$ 分的特殊性质能做,还是水平不够啊。下午复测,结果 T2 多过了 $2$ 分,就当弥补笔试了吧。看同省成绩发现不少选手失误了,感觉很可惜。晚上跟绝帆、黑塔和艾斯特尔其打羽球,爽了。

Day.1.5(7.15)

社会实践,两个馆内容还不少,也算是放松了一下。

下午去报告厅看电影《人生大事》,除了剧情略有逆天外感觉还行。

打塔,打刚开的界园肉鸽,打板子,睡觉。

Day.2(7.16)

这回没那么慌了,确实是正常发挥一次后心态就好了不少。进场开题,给 T1 胡了一个递推,写暴力过了 Pretest。开始优化,发现全是无用状态,优化到两个数组递推,想到可以直接扔上线段树大力维护矩阵,但是矩阵大小有 $5$,复杂度比较逆天就没干。又盯了一会才发现本质是找 "11" 和 "101",这个就好做多了,区间取反也不难。但想到这已经快俩小时了,写完又因为讨论错了虚空调试若干分钟,三个小时才过。

之后看 T2,感觉困难完了啊,先写 $8$ 分跑了。看 T3,二分是不是挺有前途,但线性 check 似乎不太容易,想了好久才想到 DP 维护合法区间,也调了好长时间,过 $35$ 的时候只剩了半小时。又回去看 T2 部分分,感觉 A 性质或许能做,然而到结束也没想出,总分 $100+8+35=143$ 离场。

出来发现一车 $151$,原来 T2 写个按位暴力 DP 就有 $16$ 了,但我没往这方面想。复测分数没变。总之感觉尽力了,毕竟调试时间长和思路偏差都是实力的一部分。两场都没啥遗憾,应该也有铜线以上了。曹神好像 Au 了,膜拜。不过这次两场 T1 似乎都比较简单,感觉群里的银线 $410$ 有点低啊。

人们总在劳碌中 争夺片刻的安宁

盛放后也寻求独享散场的寂静 循环更替

死亡正在颂唱万物的真名

侧耳倾听 倾听生命 礼赞的回音

——《我生于死去之日。

当天晚上篝火晚会,有唱歌跳舞之类,听到稻香的时候挺激动的,感觉这对我来说是最重要的一首歌了。还有两位杏酥桐唱了蜂鸟,给我与 NOI 补上了说是。本来还在凑七人上去唱 Lemon 中文版,但摇人的时候 Cfz 就去唱原版了,出道失败。总之感觉确实放松下来了,晚上也跟初中好朋友聊到十二点多,给了我一些力量和信心。

Day.3(7.17)

上午是我与 NOI 活动,感觉大家都很牛,尤其是《凄美地》和最后绝帆的压轴,被触动到了。当然黑塔和 Cfz 唱的中 V 也很不错。下午闭幕式颁奖,$99+(100+34+8)+(100+8+35)=384$ 的成绩确实比铜牌线 $320$ 高不少。金银线分别是 $571$ 和 $410$,感觉有点抽象。SD 取得了团体第七的好成绩,感觉 lmj 真王朝了。曹神和策队两金,还是太牛了。

晚上还是打塔,打集,睡觉,一夜无话。

Day.4(7.18)

上午九点四十坐大巴到了绍兴北,发现进出站口的广场修好了,差点没认出来。

和 ysy,tmc 同一班车,十一点坐到五点。路上随便写了点梦熊模拟赛题解,睡了会觉,最后开了个题但没写完,之后再写吧。

就这样结束了,我的首个赛季也真正结束了。下面的内容并非记叙,可能算是一些追忆和感慨吧。

别听成绩外都没意义

说教着要脚踏实地

却不告诉我最大前提

是必须先折断羽翼

……

让我不后悔每个决定

情绪一键恢复冷静

我不该这样死在原地

我就该活在自由里

——《理想主义患者

回顾整个赛季,我似乎挺幸运的。CSPNOIP 时水平很低,但发挥正常乃至超常,取得了一点成绩,才让我有了些许冲省选的勇气。虽然现在看来当时根本没实力,但事实上还是走到了这里,以 D 类的身份站在了 NOI 的赛场上。还有 WC 划线时恰好被卡,结果后来又幸运递补,让我有了参赛资格,也开始了我在 OI 圈的社交。

然而或许也有些不幸,经历了 WCAPIO 的两场惨败。每次我都有些自我怀疑,怀疑自己是否应该走下去。所幸最后这场 NOI 虽然分数不高,但至少打破了先前两场比赛给我留下的梦魇,也给了我一些信心。

同时,这场 NOI 让我目睹了不少选手的失利,也宣告了许多选手的退役。OI 或许就是这样变化无常,“李广无功缘数奇”的悲剧似乎格外多。在为他们惋惜的同时,我对 OI 的认识似乎也深了些,也有些犹豫是否要继续。但想到自己的兴趣和过去一年半的努力,想到家长对自己的大力支持,想到教练的教导和帮助,想到好朋友鼓励的话语,最终还是决定继续。无论结局如何,至少不留遗憾。

因此之后还是主要学 OI,至少会冲到明年省选。总之还是祝大家不管 OI 还是 whk,都能有令自己满意的美好前程吧。言尽于此,最后两句话与大家共勉:

风物长宜放眼量,心胸要开阔。

你不需要很厉害才能开始,你需要开始才能变得很厉害。

25.07-SDSC 模拟赛题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-08-17 11:58:56

风物长宜放眼量,心胸要开阔。

只写了感觉比较有意义的题。

D1T1 最大公约数

题意

给出长为 $n$ 的序列 $a_i$,可进行一次区间加 $k$ 操作,求操作后全局 gcd 的最大值。多测,$T\le 5,n\le5\times10^5,a_i,k\le 10^{18}$。

题解

观察一下答案结构,是前后缀各一段再拼上中间加 $k$ 的形式。又由于前缀 GCD 只有 $O(\log V)$ 段不同取值,猜想每段有用的 $l$ 很少。事实的确如此,若结尾在 $[L,R]$ 内的前缀 GCD 均为 $g$,则 $l=R+1$ 在 $l\in [L+1,R+1]$ 中一定最优。证明考虑最终答案是 $g_L,g_M,g_R$ 三者的 GCD,而这段 $l$ 对应的 $g_L$ 均为 $g$,此时把尽可能少的数划到中间一定更优。同理也只有 $O(\log V)$ 个有用的 $r$。

可以直接类似枚举所有有用的 $l$,同时只在有用的 $r$ 处统计答案。这里由于 GCD 不变时函数只会运行 $O(1)$ 次,直接维护中间部分 GCD 就是 $O(n+\log V)$ 的。由于统计答案时还要算一次 GCD,总复杂度为 $O(n\log V+\log ^3V)$。

也可以直接暴力枚举所有合法对 $[l,r]$,$g_L$ 和 $g_R$ 容易前后缀预处理。考虑使用 ST 表维护区间 GCD,复杂度 $O(n\log^2V+\log^3 V)$,但 chb 说这个是均摊 $O(n\log V)$ 的,不懂,反正不好过。

事实上注意到关键点只有 $O(\log V)$ 个,考虑只对这些点建 ST 表,即 $w_i$ 表示两个关键点之间的 GCD。预处理 $w_i$ 只需 $O(n\log V)$ 的复杂度,对 $w$ 建出 ST 表后枚举区间即可,总复杂度也是 $O(n\log V+\log^3V)$。

D1T2 回家路径

题意

给出 $n$ 个点 $m$ 条边的有向图,经过每条边需要花费 $w_i$ 元。初始有 $p$ 元钱,在 $i$ 点上每次可赚 $a_i$ 元,求可从 $1$ 走到 $n$ 的最小赚钱次数。多测,$T\le 5,n\le 800,m\le 3000,p,a,w_i\le 10^9$。

题解

考虑路径确定时如何赚钱最优,显然只会在 $a_i$ 前缀最大值处赚钱,否则一定可以在前面的点赚更多的钱,且不会导致方案非法。因此可 Dijkstra 预处理出所有点对间的最短路 $d_{i,j}$,根据上面的结论枚举前缀最大值,因此只会进行 $a_i<a_j$ 的 $i\rightarrow j$ 转移。状态内记录 $(c,t)$,表示到该点至少需要赚 $c$ 次钱,此时最多剩余 $t$ 元。显然在 $c$ 最小的前提下令 $t$ 最大最优,因为 $c$ 大时完全可以将多出的次数放到后面更大的前缀最大值处赚。因此按 $a_i$ 排序后可直接转移,每次多赚若干次钱并计算新的 $(c',t')$ 即可,时间复杂度 $O(nm\log m+n^2)$。

原题

P13534

D1T3 树上划分

题意

给定一棵树,对其划分连通块,最大化每个连通块的次大值之和。$n\le 5\times 10^5,a_i\le 10^9$。

题解

考虑最终连通块的结构,注意到每个连通块只保留最大值和次大值之间的路径即可,其他点可以放到别的连通块中使得答案不降。因此存在最优解为路径划分,问题转化为划分路径,求每条路径两端点较小值之和的最大值。由于取到更小的值一定不优,这样求出的结果不会超过答案,显然也能取到最终答案。

考虑对此进行树形 DP,设 $f_{u,i}$ 表示以 $u$ 为根的子树中,$u$ 点向下连到了值为 $i$ 的点,且该路径未完全确定,子树内其他路径权值和的最大值,$g_u$ 表示 $u$ 点已被占用时子树内权值和最大值。转移时依次合并每个子树 $v$,有 $f_{u,i}=\max(f_{u,i}+g_v,f_{v,i}+s),g_u=\max(g_u+g_v,f_{u,i}+f_{v,j}+\min(i,j))$,其中 $s$ 表示之前合并过的子树 $g$ 的和,使用一些前后缀优化可以做到 $O(nV)$。

使用线段树合并优化该 DP,对 $f$ 的 $i$ 一维开线段树存储 DP 值,转移时将两线段树内的元素带权合并起来即可。$g_u$ 需要求 $\max (f_{u,i}+f_{v,j}+\min(i,j))$,这个可以在合并过程中处理,在每次递归到子树之前用左右子树更新答案即可,细节较多,时间复杂度 $O(n\log n)$。

D1T4 还原排列

题意

给出序列 $b$,可还原出一个排列 $p$,使得 $\forall i,\sum_{j<i}[p_j>p_i]=b_i$,即其前面有 $j$ 个更大的数。要求支持单点修改,询问某个 $p_i$ 可能的最小值,保证有解。$n,q\le 2\times 10^5$。

题解

考虑如何还原,可以正序处理,$b_i$ 即其在前 $i$ 个数中的相对排名;也可倒序处理,维护目前剩余的值,即可找到第 $b_i+1$ 大的值赋给 $p_i$。由此可见排列是唯一的,题意中的最小值只是诈骗,上面也给出了一种单次 $O(n\log n)$ 的做法。

考虑先优化到单次 $O(n)$,注意到只询问 $p_i$ 一个值,上面的做法却还原出了整个排列,比较浪费。考虑从 $i$ 不断向后扫,并维护 $r$ 表示目前比 $p_i$ 大的数有多少个。那么扫到 $b_j$ 时若 $b_j\le r$,一定有 $p_j>p_i$,给 $r$ 加上一;否则 $r$ 不变。最终 $n-r$ 即为所求。

再用数据结构优化该过程,注意到每个 $b_i$ 会使后缀的一段 $r$ 加一,若把 $(r,r')$ 画在坐标系上,会以 $b_i$ 为分界线形成两段一次函数。此时若再经过 $b_{i+1}$,会再将 $r'\ge b_{i+1}$ 的部分向上平移,从而得到三段一次函数。据此经过 $c$ 个数时,会形成 $c$ 段一次函数。

考虑快速合并两组一次函数。用 $f_c,g_d$ 分别表示两组,每个值表示该处比上个函数该处大 $1$,作为新一段的开头,也即 $[f_i,f_{i+1})$ 内的数经过后会加 $i$。则新的 $h_i=\min_{j+k=i}(f_j,g_k-j)$。注意到若 $h_i$ 在 $(j,k)$ 处最优,则 $h_{i+1}$ 一定在 $(j+1,k)$ 或 $(j,k+1)$ 上最优,因此可类似归并合并,复杂度 $O(c+d)$。

这样就可以直接上线段树维护区间函数,线段树的 pushup 复杂度为 $O(len)$,单点修改时要重新向上合并到根,复杂度 $O(n)$,查询时可直接在 $O(\log n)$ 个节点的函数上依次二分,总复杂度为 $O(q(n+\log ^2n))$。

由于修改复杂度远大于查询,考虑用分块平衡复杂度。将序列每 $B$ 个元素分一块,块内用线段树维护区间函数。这样修改复杂度降到 $O(B)$,询问时先将本块内的单点暴力扫完,再依次在后面的 $O(\frac nB)$ 个块上二分处理即可。总复杂度为 $O(q(B+\frac {n\log n}B))$,平衡至 $B=\sqrt{n\log n}$ 得到最优复杂度 $O(q\sqrt{n\log n})$。

原题

CF1540D

D2T4 树上监控

题意

给定一棵树,每个点有价值 $a_i$。现要在至多 $k$ 个点上放置监控,监控可以观测到距离不超过 $r$ 的所有点,求被观测到的节点价值和的最大值。多测,$T\le 10,k\le n\le 10^3,r\le 10^3,1\le a_i\le 10^6$。

题解

注意到 $kr\ge n$ 时,一定能将整棵树全部覆盖,方式是找到深度最深的叶子,并在其 $r$ 级祖先上放置监控,这至少会删掉该祖先子树中的至少 $r$ 个点。因此放 $k$ 次一定能覆盖完,只需要解决 $kr<n$ 的问题。

然而 DP 状态难以设计,原因是覆盖距离 $r$ 导致可能被父亲方向很远的点覆盖,因此考虑预先钦定每个点最终是否被覆盖,设 $f_{u,i,x_1,x_2}$ 表示 $u$ 子树内放置了 $i$ 个监控,最深的钦定却未被覆盖的点距 $u$ 点 $x_1$,最浅的监控距 $u$ 点 $x_2$ 时子树内最大贡献值。

显然 $x_1+x_2>r$ 的状态才有意义,否则不会未被覆盖。另外此时若 $x_1$ 存在,则子树外一定会放一个监控覆盖到它,且其在子树外的覆盖范围不小于子树内任意一个监控。因此此时不需要记录 $x_2$,之后用子树外更优的进行覆盖即可。

于是 $x_1$ 不存在时记录 $x_2$,$x_1$ 存在时只记 $f_1$,因此设 $f_{u,i,x_1},g_{u,i,x_2}$ 分别表示两种情况下 $u$ 子树内放 $i$ 个监控的最大值。每次拼上一个子树,写出转移式后可以发现新的 $x$ 值一定为 $x$ 或 $x+1$,且另一个值有前后缀限制。因此对每个 $(u,x)$ 预处理前后缀 max 值优化转移,可以做到每个状态 $O(1)$,总复杂度根据树形背包为 $O(nrk)$,根据前面的性质不会超过 $O(n^2)$,具体转移式此处略去。

原题

P4845

D3T3 耳后的呼吸

题意

有 $n$ 个开区间,保证存在一个公共点,问多少次将某区间平移 $1$ 个单位后能使其两两不交。$n\le 5000$。

题解

设公共点为 $x$,则先整体向左平移 $x$,使得存在 $0$ 为公共点。若 $n$ 为奇数则会把除中间区间外的区间平分到两边,这时中间区间不需要移动;若 $n$ 为偶数可添加一个区间 $l=r=0$,显然其也不会移动。推一推式子发现若左右各 $c_1,c_2$ 个区间,最终代价为 $c_2r_m-c_1l_m+\sum_{i=0}^{c_2-1} i\cdot len_i-\sum_{i=0}^{c_1-1} i\times len_{i}$,其中每部分按照 $len_i$ 降序排序最优,在数轴上即越长的区间越远离原点,这也能解释 $c_1=c_2$ 最优。

据此可直接枚举不动的区间,并 DP 设 $f_{i,j}$ 表示前 $i$ 个区间选了 $j$ 个在左的最小代价,时间复杂度 $O(n^3)$。然而发现中间区间只会决定 $l_m,r_m$ 的取值,因此直接设 $f_{i,j,0/1}$ 表示是否已经选出中间区间时的最小代价即可,时间复杂度 $O(n^2)$。

D4T2 很简单题

题意

$h$ 个点 $n$ 条边,$q$ 次询问在边权为 $0$ 的完全图中加入 $[l,r]$ 内的边形成的最大生成树。$h\le 10,n,q\le 5\times 10^5$。

题解

Sol.1

直接暴力上线段树,每个节点上记录该区间内最小生成森林的所有边,至多 $h$ 条,合并时用 $2h$ 条边跑最小生成树即可。时间复杂度 $O(n\log nh\lpha(h))$,由于常数较大,跑不过。

Sol.2

用 $h^2$ 个 ST 表维护每种边的最大权值,直接维护需要 $O(h^2n\log n)$ 的空间,会爆。因此改为对每个询问维护 $h^2$ 种边的最大值,然后枚举每种边,建出 ST 表后对所有询问更新,空间复杂度优化到 $O(qh^2+n\log n)$。对每个询问用 $h^2$ 条边跑 Prim,时间复杂度为 $O(h^2n\log n+qh^2)$。

Sol.3

Sol.1 中的 $h^2$ 个 ST 表内其实总共只有 $n$ 个元素,因此可以只建大小为 $cnt$ 的 ST 表,查询前映射过去。由于总元素个数有保证,建 ST 表的总时空复杂度为 $O(n\log n)$。比较暴力的映射方式是记录出现的位置,从而二分出左右端点,时间复杂度 $O(qh^2\log n)$,跑不过。

考虑去掉二分,直接对每种边开两个长为 $n$ 的数组,记录每个位置左边第一条和右边第一条该种边的编号即可,空间复杂度 $O(h^2n+n\log n)$,时间复杂度 $O(n\log n+h^2n+qh^2)$。

Sol.4

是另一种优化取最小值的方式。考虑直接对边的编号 $[1,n]$ 分治,每次处理所有跨过中点 $mid$ 的所有询问,再把其余询问递归下去处理。具体地,每种边在 $[l,mid]$ 内处理一个后缀最小值,$[mid+1,r]$ 内处理一个前缀最小值,询问时把前后缀拼起来即可得到每种边的最小权值,最后同样再跑 Prim 即可。空间复杂度 $O(h^2n)$,时间复杂度 $O(h^2n\log n+qh^2)$。

Sol.5

是 chb 的做法。将 Sol.4 的分治与 Sol.1 的维护方式结合起来,每次预处理前后缀最小生成树内的边。这时每次只会加一条边,因此不需要重跑 Kruskal,只需要在原树中 DFS 求路径最大值,并试图用新边替代最大边即可,复杂度 $O(h)$。询问时将前后缀 Kruskal 拼起来得到答案。时间复杂度 $O(hn\log n+qh\lpha(h))$。值得一提的是本题的 $\log n>h$,因此本做法算复杂度可能没有 Sol.3 优。

D4T4 特简单题

题意

维护一个环,每个点的贡献为经过的 $a$ 最大值乘 $a_i$,需要支持区间覆盖,区间修改,查询给出 $i,z$,询问从 $i$ 开始走到第一个贡献大于 $z$ 的点。$n,q\le 2\times 10^5$。

题解

下文中所有 $p$ 均表示前面走过的最大值。

考虑使用数据结构维护每个区域的贡献,再在该数据结构上二分。由于某个区域的贡献会受到前面最大值的影响,考虑使用单侧递归线段树。在每个节点上维护区间长度 $l$,$a_i$ 的最大值 $x$ 以及只经过该区间的总贡献 $w=\sum a_ip_i$,区间修改为 $k$ 时有 $x=k,w=lk^2$。

然而区间加只维护这些是不够的,区间加 $k$ 时对 $w$ 拆开 $\sum(p_i+k)(a_i+k)$ 得到 $\sum p_ia_i+kp_i+ka_i+k^2$,因此需要维护 $s=\sum a_i,d=\sum p_i$,即有 $w'=w+kd+ks+lk^2$。$s,d$ 修改为 $k$ 时均会变成 $lk$,区间加时均会增加 $lk$,就实现了所有的区间修改。

因此可以类似普通线段树用两个懒标记维护,注意覆盖标记会清空加标记,区间加时若有覆盖标记则加给覆盖标记,懒标记的下传也是容易的。现在需要实现的是 pushup 合并两个区间的操作,这种贡献与前面值有关的合并需要单侧递归。

具体地,设 $lc,rc$ 为线段树上左右儿子,现需合并 $L=lc_u,R=rc_u$ 的信息到 $u$。显然 $L$ 的信息均不变,而 $R$ 的信息可能会受到 $x_L$ 的影响。考虑再将 $R$ 分成 $lc_R$ 和 $rc_{R}$ 两部分,若 $x_{L}\ge x_{lc_R}$,则 $lc_{R}$ 内均以 $x_{L}$ 为 $p$,容易计算,因此记录 $x_L$ 并递归到 $rc_{R}$ 计算贡献;否则 $x_L<x_{lc_R}$,$x_L$ 一定无法越过 $lc_R$,$rc_R$ 的贡献为其在 $R$ 节点内的贡献,可用 $w_R-w_{lc_R}$ 计算,因此记录 $x_L$ 并递归到 $lc_R$ 计算贡献。

每次只会向左右子树中的一个递归,因此单次 pushup 的复杂度是 $O(\log n)$ 的。实现上只需要写成函数,对某节点传入一个前面经过的最大值 $p$,返回其内部考虑上前面的 $p$ 时的信息。上面其实就是调用 $(R,x_L)$ 的过程,具体可能要对 $d,w$ 分别写函数。

这样就以单次修改 $O(\log^2n)$ 的复杂度维护出了任意区间的信息。询问时考虑在线段树上二分,先求出能走到第一圈的哪个位置,过程中还是要带着前面的最大值,需要将该值传到函数里 $O(\log n)$ 确定当前节点的贡献。后面部分需求出最后一圈走到哪个位置,这里只对 $s$ 二分即可。实现起来细节比较多,还要考虑跨过环的情况,时间复杂度 $O(q\log ^2n)$。

D5T1 以史为鉴之习

题意

给出一个长为 $n$ 序列 $a$,$q$ 次询问 $[l,r]$ 区间内数的乘积是否是完全平方数。$n,q\le 2\times 10^5,a_i\le 10^6$。

题解

区间乘积为完全平方数当且仅当所有质因子的次数均是 $3$ 的倍数,考虑直接使用哈希,对每个前缀所有质因子的次数对 $3$ 取模的结果计算出哈希值 $s_i$,则 $[l,r]$ 合法当且仅当 $s_r=s_{l-1}$,时间复杂度应该可以线性。

也可以用莫队做,直接暴力维护所有质因子的次数,同时记录变量表示目前次数不为 $3$ 的质因子个数,每次区间变化就对 $\omega(a_i)$ 个质因子修改,时间复杂度 $O(n\sqrt q\omega(V))$。然而可以接受枚举 $\sqrt V=1000$ 以内的质因子,对这些用前缀和暴力枚举,之后只剩至多一个大于 $\sqrt V$ 的质因子,只对这个进行莫队即可,时间复杂度 $O((n+q)\sqrt V+n\sqrt q)$,事实上质因子个数远小于 $\sqrt V$。

D5T4 业报插翅难逃

题意

给出一个序列 $a_i$,求有多少种重排方式使得相邻两数之积均不超过 $w$。$n\le2000,\left|a_i\right|\le 10^9,2\le w\le 10^9$。在 $a_i\ge 0 $ 时 $n\le 10^6$。

题解

先考虑 $a_i\ge 0$ 怎么做,发现原来的限制很抽象。考虑构造一个排列 $p$,使得 $\forall i\in[1,n]$,要么 $\forall j<i,a_{p_i}a_{p_j}\le w$,要么 $\forall j<i,a_{p_i}a_{p_j}\gt w$,再按照这个顺序加入就会好做很多。具体构造考虑先按 $a_i$ 从小到大排序,此时若 $a_1a_n\le w$,则 $a_1$ 与任意数相乘均合法,将其放到结尾并删除;否则 $a_n$ 与任意数相乘均不合法,同样放到结尾并删除。这样就构造出了一个符合要求的排列。

之后考虑 DP,设 $f_{i,j}$ 表示考虑了前 $i$ 个数,目前还有 $j$ 个连续段的方案数。若新开一个连续段有转移 $f_{i+1,j+1}\leftarrow (j+1)f_{i,j}$,当某个数与前面均不合法时只能进行这种转移。若合并两个连续段有转移 $f_{i+1,j-1}\leftarrow (j-1)f_{i,j}$,若接在某连续段两边有转移 $f_{i+1,j}\leftarrow (2j)f_{i,j}$,答案为 $f_{n,1}$,时间复杂度 $O(n^2)$。

当正负均有时,由于异号相乘为负一定合法,直接分两组分别进行上述 DP,之后枚举两种的组数拼起来,若组数相等则乘 $2$,相差 $1$ 则不乘,对方案数求和即为答案,时间复杂度仍为 $O(n^2)$。

对于 $a_i\ge 0$ 还有一种神秘做法,考虑先按 $a_i$ 排序,并对每个数决策其前驱,则每个数能取前 $p_i$ 个数。之后倒着枚举所有 $p_i$,则其一定递增,因此有 $p_i-(n-i)+1$ 个可选的数(包括空,代表其为开头)。然而前驱不能选自己,因此容斥钦定 $S$ 中的数前驱选自己,其他不管。

这时答案为 $(-1)^{\left|S \right|}\prod_{i\notin S} p_i-(n-i)+1$,之后发现这个跟 $\prod p_i-(n-i)+1-[p_i\ge i]$ 等价,证明考虑把该式前后分开,并展开乘法就是前面的式子。因此答案为 $\prod p_i-n+i+[p_i<i]$,时间复杂度 $O(n)$。

D6T1 氧气

题意

给出一个序列 $a$,要求从中选择 $k$ 个长为质数且不相交的子段,最大化所有子段和的最小值。$k\le n\le 2\times 10^5,\left|a_i\right|\le 1000$,且保证 $a_i$ 在范围内随机生成。

题解

先二分最小值,之后要求每段的和均不小于该值。之后从左往右贪心,到新位置 $i$ 且上段结尾为 $k$ 时,若存在 $j\in[k,i)$ 使得 $s_i-s_j\ge mid$ 且 $i-j$ 为质数,则可将 $[j+1,i]$ 划分为新的一段,暴力做这个过程需要 $O(n^2\log (nV))$ 的复杂度。

考虑加速这个过程,注意到要求 $s_j\le s_i-mid$,因此满足条件的 $s_j$ 是一段前缀。因此将 $(s_j,j)$ 按 $s_j$ 排序存到 set 里,每次暴力从 set 开头依次取出元素检查,若 $s_j$ 已不合法则停止,否则若 $i-j$ 为质数就将答案加 $1$ 并清空 set,再进行后面的操作。

由于整个序列是随机生成的,因此 $s$ 数组的排名也可以认为是随机的,因此期望 $O(\log n)$ 次可以取到一个 $i-j$ 是质数的 $j$。同时从 set 开头取 $c$ 个元素的复杂度为 $O(\max(\log n,c))$,因此时间复杂度为 $O(n\log n\log (nV))$。

D6T2 bmbmbm

题意

$k$ 维空间,每一维大小均为 $n$,求其中 $m$ 个超立方体两两不交的方案数,要求每个立方体每一维均满足 $l<r$。取模,$n,k\le10^9,m\le6$。

题解

首先两个立方体有交当且仅当它们每一维都有交,因此考虑在维度上 DP,即一维一维考虑。由于维度数 $k$ 过大,或许需要使用矩阵快速幂优化。考虑设 $f_{i,S}$ 表示考虑了 $i$ 个维度,$S$ 中为 $1$ 的位对应的二元组 $(i,j)$ 满足 $i,j$ 在前面的维度均有交,其余二元组已经无交的方案数。$S$ 的长度为二元组个数 $e=\frac{m(m-1)}2\le 15$,状态共有 $2^{15}=32768$ 个,转移式为 $f_{i,S}\times g_T\rightarrow f_{i+1,S\cap T}$,即枚举该维相交状态 $T$,其中 $g_T$ 表示一维内相交状态为 $T$ 的方案数。

需要预处理出 $g_T$,这里使用暴力搜索。由于维度大小 $n$ 也很大,考虑拿出其中作为区间端点的关键点,显然个数在 $[2,2m]$ 内。首先枚举关键点个数 $len$,再钦定顺序为先按左端点从小到大,再按右端点从小到大排序,同时要求不能有关键点没被选过。加上这些剪枝后跑得飞快,在 $m=6$ 时没有超过 150ms。

这样我们就得到了所有只保留关键点的区间方案,也容易计算出其对应的原问题方案数和相交情况 $T$,注意这里原问题方案数为 $n\choose len$ 乘上不同区间的多重集排列数。这样所有方案的方案数之和为 ${[\frac{n(n-1)}2]}^m$,即所有不同的区间选择方案。然而由于顺序已被钦定,还是难以推到每个 $g_T$ 的具体值。这里考虑对于两种状态 $S,T$,若忽略其编号后形态相同,则这两种状态本质相同,也有 $f_{i,S}=f_{i,T}$ 和 $g_{S}=g_T$。因此再写一个搜索搜出所有等价类,共 $c=156$ 种。具体实现上先枚举所有状态,再阶乘枚举置换即可。以下记 $S$ 所在的等价类为 $id_S$。

之后设 $h_i$ 表示 $i$ 等价类内的 $g_T$ 之和,$t_i$ 表示 $i$ 等价类内的状态个数。这样先让上一段中提到的相交情况 $T$ 贡献到 $h_{id_T}$,最后再令 $g_T=\frac {h_{id_T}}{t_{id_T}}$ 即可,由于等价类内数量相同,该式一定成立。同时等价类数量 $c$ 也已经能接受 $O(c^3\log k)$ 的复杂度,直接套矩阵快速幂优化即可,实现上有诸多细节。另外求出 $g_T$ 后,由于转移形如 And 卷积,可以 FMT/FWT 后直接快速幂计算,可做到 $O(2^e(e+\log k))$ 的复杂度,会快一些。

D6T3 ゆきこ

题意

对于一个排列 $p$,设 $f(p)=\sum\min(i-l_i,r_i-i)$,其中 $l_i,r_i$ 分别表示 $i$ 左右第一个比其大的位置。$T$ 次询问给出 $n,x$,求有多少个长为 $n$ 的排列 $p$ 满足 $f(p)=x$,对某模数 $P$ 取模。$n\le 300,x\le 10^9,T\le 10$。

题解

先考虑 $f(p)$ 的上界,设 $g_n$ 表示长为 $n$ 的排列 $f(p)$ 最大值,枚举最大值位置有 $g_n=\max_{i=1}^n(g_{i-1}+g_{n-i}+\min(n-i+1,i))$。该过程类似启发式合并,因此 $g_n$ 不会超过 $O(n\log n)$ 级别,事实上常数很小。

设 $f_{n,i}$ 表示长为 $n$ 且 $f(p)=i$ 的排列数量,则有 $f_{n,i}=\sum_{j=1}^n \sum_{k=0}^if_{j-1,k}\times f_{n-j,i-k-\min(n-j+1,j)}\times {n\choose j-1}$,复杂度为 $O(n^4\log^2n)$,无法通过。注意到第二维全是加起来,且大小并不大,考虑改成用多项式维护 DP 值,即 $F_n$ 表示长为 $n$ 的排列 $x^{f(p)}$ 之和,是一个 $O(n\log n)$ 次多项式,暴力转移就是上面的式子。

考虑放弃维护整个多项式,而是只维护多项式实际值,可以避免 $O(n^2\log ^2n)$ 的转移复杂度。由于次数 $k$ 为 $O(n\log n)$,只需要知道 $(k+1)$ 个实际值即可还原其系数,因此维护这么多个值即可。设 $h_{n,x}$ 表示 $F_n$ 在 $x$ 处的取值,转移即为 $h_{n,x}=\sum_{i=1}^n h_{i-1,x}\times h_{n-i,x}\times x^{\min(i-1,n-i)}\times {n\choose i-1}$,这样复杂度变成 $O(n^3\log n)$,跟原来相比转移优化到了 $O(n)$。

这样询问 $n,x$ 时,用 $h_n$ 的若干值拉格朗日插值还原出 $F_n$,$x$ 次项系数即为答案。单次还原是 $n^2\log^2 n$ 的,因此总复杂度为 $O(n^3\log n+Tn^2\log^2n)$。

D7T1 Were

题意

给定 $x,k$,求经过若干次求数位和或加 $k$ 操作后能变成的最小值,以及变成该值的最少操作次数。多组数据,$T\le 10^3,x,k\le 10^{15}$。

题解

注意到求数位和不会改变对 $9$ 取模的值,因此最终最小值一定为 $\min_{i=0}^8 w(x+ik)$,第一问答案就有了。同时 $10^{16}$ 以内的数最多取 $3$ 次数位和就只剩一位了,因此总操作次数 $c\le8+3=11$,枚举所有操作序列即可,复杂度 $O(Tc\cdot2^c)$。

NOIWC2025 游记

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-01-23 22:01:01

(由于这次 WC 本来也没想拿牌,实际上也没拿到,所以本文与日程安排一致,以 1.17 为 Day.1)

神魂游荡生梦处,一瞥风雪中。

角兽踪迹银铃音,恍惚至彼端。

Day.-3inf

某天教练过来问要不要报名,原本说太难了打算不报,后来又报上了,不知道能不能过。

Day.-2inf

事实上是在 NOIP 结束返程的车上,得到了 WC 线是 $316$,这下差 $4$ 分遗憾离场了。

Day.-inf

开始备战省选后的某天,教练说我又递补上了???这也太牛了,开心,肯定要去啊。

Day.0

凌晨四点从 THUWC 坐火车到家,睡饱以后起来搞了会校内模拟赛,大部分时间还是摆了。

Day.1

八点的火车,上车时 Iceturky 已经在车上了,我们很巧又很不巧地是相邻车厢的同一个座位,换了换座坐一块了。十二点在宇宙中心南京南换乘,最后三点多到的。发了有 CCF 标志的书包,里面放了讲义餐票之类的,然后就去宿舍了。

同校正好四个人一个屋,还有 cxm 和 chb。宿舍条件还挺不错的,食堂吃得也不错。搞笑的是发现另外三人在名单和胸牌上的学校名错了,“山东省”都打成了“山东生”,不知道是不是教练弄错的,我可能因为是递补免遭此劫。

下午就逛了逛校园,摸到了第一课堂和第二课堂的位置。晚上有开幕式,面基群里全程复读。首先是不知道为啥有变脸,然后是抽象的按按钮启动,只有后面那个展示汉服的节目还不错。最后是杜子德主席讲话,比较有意思,贴上链接

晚上回宿舍后打 CF,被 D 卡整场,幸好前面手速快,还是上了一点分。

Day.2

上午是 zak 的非确定性算法,听懂的不太多,后面就直接掉线了;下午是 Rainbow 的图连通性问题,听懂的不太多,后面就直接掉线了。两位老师都在讲课时高强度看面基群并答疑,有点牛的。

晚上虽然有论文交流但没去,看了看粥的春节前瞻,八点开始打 ABC。结果被 E 的 corner case 卡爆,起初还以为是 __int128 爆了,改了好几发发现还不对,才逐渐想到 corner case,第九发才过的,然后暴写 F 线段树才没掉分,上了 $1800$。

Day.3

上午第一课堂讲 AI 相关,同时第二课堂讲网络流,直接去第二课堂了。老师讲得还不错,三小时速通了一堆东西。下午 Kubic 好题选讲,每个题都不到一半就听不懂了,太困难。另外下午跟 Linge_Zzzz 交换了徽章,这也是除了早认识的 Iceturky 之外换到的唯一一枚徽章。

晚上 cxm 在打 Galaxies,被带入坑。玩的时候教练来给了密码条,宿管来告知了第二天的日程安排。然后看了粥的新春会,嘉平歌真好听。十点多大家就早早熄灯睡了。

凄厉号声震天响,孤木成众林。

击鼓燃叶唤先灵,低语解哀戚。

Day.4(比赛日)

这一天发生了很多事,所以篇幅会比较长。

早上七点起了,吃了饭排队去学校对面的比赛场地。试机,有一些糕点 + 士力架 + 一瓶水作为物资。然后把我们赶出来重新进场,十点就正式开始了。有 Self Eval 作为 Pretest,挺好。

下面要开始寄了。开场看了一遍题以后开 T1,推推推推推推,困难困难困难,这东西我怎么不会,哎 WC 不会也正常,一个半小时写完 $45$ 暴力跑了。看 T2,什么抽象东西,直接暴力,我怎么只会 $V^n$,$16$ 分输出方案还难写,不管先写了。看 T3,$5$ 分直接贪快速写了。

这时还有两个半小时,由于我误以为 WC 会很困难,所以在冲 T1 和写暴力中选择了后者,然后找到了觉得最能写,实际上却很困难很麻烦的 T2 A 性质。写就用掉了一个小时,然后一直没分一直调,直到最后也只有一半 $6$ 分,最后 $45+22+5=72$ 遗憾离场,拿走了包括厕所牌在内的四张牌。

出场跟 Iceturky 一对,他听到我 T1 没过一脸惊讶,指出每只猫只会吃两袋猫粮。天塌了,因为我并没有观察到这个性质,导致一直不会做,这样的话只需要两两匹配就行。后来聊了聊发现我 T1 其他的性质都注意到了,甚至 corner case 都在暴力里写了,就是没有发现最关键的那条。

在群里发现除了 T1 全场几乎全切,我的 T2T3 部分分也非常低,T3 还是不太难的线段树优化 DP,切的也不少,也是我可能比较擅长的题。这下稳稳打铁了,打得真挺烂的。吃了饭睡了会又回去复评,我其实已经心如死灰了,本来还想补补 T1 发现根本没心情写,拿着纸质题面就走了。

后来一直在安慰自己,其实感觉也能接受吧,反正这场比赛并不那么重要,自己的水平本来也是打铁。毕竟这是我认真参加的第一场省选级别的比赛,判断失误感觉也正常,而且这样给自己一个教训的话,或许省选就不会出同样的问题了。后来看到大家都在群里骂比赛,吃晚饭的时候 Rainbow 还在群里发了分数线,发现我即使过了 T1 也不太能拿铜,心里又好受了点。

晚上去报告厅先讲题,结果二十分钟速通了,直接开文艺汇演(这是录像)。首先是一段草台班子,幻灯片第一页 42st,然后电脑没声音开始重启,重启又开始 Windows 系统更新,十分多钟才真正开始,反正节目效果是有了。感觉那个相声很牛,钢琴很牛,花开忘忧很牛,然后 君色に染まる 和 命に嫌われている。也很牛,Iceturky 动作丰富的节目也很牛。

说实话感觉文艺汇演放比赛日确实有道理的,比如我这种完全打崩了的也能暂时忘却,开开心心地玩一晚上。另外唱命嫌之前提到不要被挫折打倒之类,结语提到比赛不是唯一目的,WC 有更多诸如结交朋友的意义之类,都给我带来了一些慰藉(虽然我这时还没交到多少朋友),事实上十点多开完汇演时,我也差不多放下上午的比赛了。

结束以后冲刺回宿舍,准备开 CF Div.1+2,大家都在打。结果吃满罚时,其中包括 B 的两发。最后做完 F1 上床颓了一会,然后开始睡觉。结果没睡着就被 chb 告知我 B 寄了,天又塌了,不过没下午塌得厉害,不管了先睡吧。

彩虹瓮中月影里,所愿纷然至。

Day.5

起床第一件事先看 CF,发现一片 B 被卡的,又是 corner case 忘判了并且 Pretest 没卡。幸好这个还冲掉我 B 两发罚时,最终还是上了一点分。

一整天都没有第二课堂,所以上午还是去了第一课堂,是随机性在算法设计中的应用,没到一半就觉得有点没意思,后半程开了把 Galaxies 15x15 Unreasonable,最后也没打完。下午第一课堂是 Flower 的动态图还是啥,太困难直接留宿舍里了,做了做杨爹给的一道好题,感觉很牛。

晚上刚认识不久的 wyd 攒局打狼人杀,本来因为谁也不认识又不会玩,准备只去凑热闹观战,结果正好缺人就跟着打了 $12$ 人局。大家大部分都是新手,打了两把猎人一把女巫,其中出现了包括女巫报错银水之类的趣事,玩得很开心。

玩的过程中大家都熟了起来,最后也建了个群。另外坐在旁边的 zfy 看到我头像问我怎么是罗神,一看就也是皱皮,还加了个粥好友。这下交到了不少朋友啊,开心。

Day.6

两节课都是科技,下午还是模拟退火,八节课有三节随机化说是,就都没去上。上午狼人杀没凑起来,就自己补了补前几场比赛的题,下午过去打了三四把。

晚上大家又都聚起来了,开场前趁机给仨人塞了自己送不出去的徽章。由于八点有 CF,玩了一把就回自己宿舍了,结束的时候只给 lhl 塞了一个,还有很多人没来得及塞。

晚上的 CF 成功切到 E,但是 E 想了一个我自认为自然却被说逆天的树剖 + 线段树做法,并在结束前二十分钟写完,然而由于多测树剖 $son$ 未更新喜提 RE 最终未能调出,遗憾离场,并非成功。然而还是由于前面手速够快涨了一点分,上了 $2000$。

Day.7

上午是论文答辩,论文是完全听不懂,但是问答环节杜子德主席发力了,在前五个选手的提问中分别影射了带手机、直播、开公司、搞关系、换省换校,大家都很乐。挂个链接

下午三点才闭幕式,中午多睡了一会,错过了狼人杀群最后的聚会,没能把徽章塞完,可惜。闭幕式是按照奖项和成绩分的座次,我由于垫底只能坐临时加的凳子,难受。同宿舍两铜一银,结果伏笔回收了,最终颁奖的时候大屏幕上是“山东生”,难绷,就我学校没错也就我打铁了。闭幕式节目好了不少,开头是古典音乐,中间有个越剧,但是杜子德主席发言没爆典,太不牛了。

晚上回宿舍,大家都在点外卖,我还是去食堂吃的。然后回宿舍本来还想接着聚会,结果发现大部分都走了,没聚起来。估计明天返程也没啥好记的,所以就开始写游记了。

结果在 cxm 的推荐下,我们屋晚上又开了出包魔法师。并且 yrq 在外放音乐,之后逐渐变成 KTV 了。期间疯狂爆杜子德教授的梗,疯狂乐。最后还唱了难忘今宵白鸟和蜂鸟,两点多才睡。

行于高处如星辰,俯瞰霜雪色。

总之感觉这次来 WC 来得很对啊,虽然说比赛打得烂完了,上课听懂的也不多。但是至少我在比赛中得到了一些教训,上课也见识到了一些高级算法,还认识了很多优秀选手,交到了不少朋友,送出了不少徽章,收获不小,同时也过得很开心。

还是希望省选顺利,下个赛季也一切顺利。希望明年还能来 WC,毕竟我还想文艺汇演表演一下啥的

合眼匍匐入梦乡,暂离此间事。

AT_awtf2024_d 题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-02-13 20:08:15

模拟赛做到了这道题,感觉妙,写个题解。

首先发现原题等价于可以给某些数加上 $n$ 后再排成升序,这样在原序列上把加过的数排好序放到最后,剩余数排好序放到前面,只有分界点可能 $P_i>P_{i+1}$,符合原题意。

直接排序需要的交换次数为序列的逆序对数,我们在此基础上考虑给数加 $n$ 导致的变化量。首先有一个性质:若 $x<y$ 且 $P_x>P_y$,则给 $P_x$ 加却不给 $P_y$ 加一定不优。证明如下:

考虑加上 $n$ 的位置集合为 $S$,我们找到 $x<y$ 且 $P_x>P_y$,同时 $S$ 包含 $x$ 且不包含 $y$ 的所有 $(x,y)$,再找出其中 $P_x-P_y$ 最小的一对,可以证明此时从 $S$ 中删去 $x$ 并加入 $y$ 一定更优,具体见下图:

图中横坐标为 $i$,纵坐标为 $P_i$(下同),修改即为从两个红点变成两个黑点。我们分别分析修改后的变化量:

  • 纵坐标大于 $P_x+n$ 和小于 $P_y$ 的部分:贡献不变。
  • 第 $1$ 部分:不存在点,若存在 $(k,P_k)$ 则 $P_x-P_k$ 更小,$y$ 不合法。
  • 第 $2$ 部分:不存在点,若存在 $(k,P_k+n)$ 则 $P_k-P_y$ 更小,$x$ 不合法。
  • 剩余部分:分别与红点和黑点分析逆序对可知 $3,5$ 贡献不变,$6,7$ 贡献为 $-1$,$4$ 贡献为 $-2$。
  • 序列中 $P_x+n,P_y$ 变成了 $P_x,P_y+n$,逆序对减少 $1$。

以上贡献均非正,所以修改后一定更优,结论得证。

从这个结论出发,我们可推得以下两条:

  • 若 $x<y$ 且 $P_x>P_y$,则如果给 $x$ 加,一定也给 $y$ 加。
  • 若 $x<y$ 且 $P_x>P_y$,则如果不给 $y$ 加,一定也不给 $x$ 加。

所以若目前要给 $i$ 加,根据第一条所有 $j>i,P_j<P_i$ 的 $j$ 一定加过了(记数量为 $c_1$),根据第二条所有 $j<i,P_j>P_i$ 的 $j$ 一定还没加(记数量为 $c_2$),此时若 $i$ 是第 $k$ 个被加的,贡献即为 $f_i=c_1-c_2+(n-i)-(k-1)$,其中 $(n-i)-(k-1)$ 比较复杂,详见下图:

$n-i$ 为 $i$ 右边所有点,先要减掉已经额外计算的 $c_1$;另外 $c_3$ 中被选过的点还会保持 $P_j+n>P_i+n$,也要减去; 还有 $c_4$ 中被选过的点算贡献后变成了 $P_j+n,P_i$ 的逆序对,现在又变回了 $P_j+n,P_i+n$ 的顺序对,需要减去 $1$ 把贡献消去。注意到减去的三部分恰为已经加过的所有点,因此减去的值为 $k-1$。

可以发现 $c_1$ 和 $c_2$ 已经可以在求逆序对时顺便求出了,但还可以再做一些推导。显然有 $c_3=n-i-c_1$,则 $c_2=n-P_i-c_3=n-P_i-n+i+c_1=i-P_i+c_1$,所以有 $f_i=c_1-c_2+(n-i)-(k-1)=n+P_i-2i-(k-1)$。

注意到 $n-(k-1)$ 与 $i$ 的选择无关,所以把所有的 $i$ 按照 $P_i-2i$ 升序排序,枚举加的个数,选 $f$ 最小的若干个加,对所有个数取最小值即可。

另外其实需要 $i$ 的 $c_1$ 中所有点先于其自身被加,但是注意到这些 $j$ 满足 $j>i,P_j<P_i$,所以 $f_j<f_i$,一定先于 $i$ 被选了,所以做法没问题,时间复杂度 $O(n\log n)$。

这是提交记录

SDOI2025 游记

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-03-02 23:57:19

坚石高墙起群山,角盔覆冰寒。

启开慧眼识密语,鸣乎驱鬼祟。

Day.-2inf(2.3)

来了北大的梦熊冬令营,住宿条件不错。老王送了扑克,一手好牌说是。

感觉打了几场模拟赛还是有进步的,毕竟之前都没怎么打过三题的比赛,至少大概有个感觉了吧。

Day.-inf(2.11)

冬令营结束了,去人大附继续跟梦熊集训。认识了蘑菇和诗岸单推人黑塔,玩得很开心。(但是不得不说诗岸确实好听)

这里应该有这个视频

我去题怎么这么难,能补的题不到一半,寄寄寄摆摆摆。

不过说实话还是学到了不少东西,也有不少好题,等省选以后有空想搬给学弟们

Day.-2(2.26)

从梦熊回山东了。

话说当天梦熊出的模拟赛怎么有德州扑克大模拟,怄火。

Day.-1(2.27)

补了几个题,其中包括 NOIP 前机房同学推的一道数据结构和 NOIPT4。

然后打了打 QOJ 上的板子,晚上拿小号打了下 Edu,E 好难,摆了。我去怎么过这么多,我去怎么猜结论过了,上分了。

Day.0(2.28)

中午坐车去济南,路上多人一起听。

到了以后同机房的同学,还有 KingPowers 和老 zak 都来了我们屋。大家都在打农,我不会,遂打板子,结果被网络流模板卡了半下午,怄火。

晚上去周围的商场吃饭,楼梯旁有滑梯,大家都在玩,但我被卡住从半道翻出来了。吃完饭去超市买东西,我啥也没买,但值得一提的是在超市看到奶龙了。

试机,遇见了同考场的 cxm、hjr 和黑塔,突然发现自己认识的人也逐渐变多了。在考场顺着板子赛写了点分治,没调出,怄火。回酒店调出来后摆了一会就睡了。

草木兽羽有枯荣,祈愿久延存。

不见生机不见移,终古长静寂。

Day.1(3.1)

进场,开题。

T1 这是啥,感觉答案好像是一段区间啊,好像又不大对。哦 $l_1=r_1$ 的时候是一段区间,二分 check 的话,跨过 $x$ 的都选 $x$ 就行,剩下的和 $x$ 大小关系确定。那一个操作就只有三种贡献,$n$ 个操作只有 $2n$ 个分界点,本质不同的区间只有 $2n$ 个啊,区间加分讨一下做完了,直接上树状数组,我写写写。我超样例全过了,两组 0.4 秒,那三组肯定行,不管了。

哇怎么才一个小时,这不赢麻了。看后面的题,哇怎么这么困难,先写暴力。写了一个半小时终于战胜 $20+8$,看看还有啥性质,怎么这么多我哪个都不会,最终 $100+20+8=128$ 遗憾离场了。

出场发现好多 $128$,这就是大众分吗。T2 好像是分块 + bitset,Iceturky 会 C 性质,我只想到 bitset 但是没想出怎么实现。讨论了一下又发现 T1 差分就行。都不管了,至少没啥遗憾。

在 chb 带领下去吃了 KFC,爽。回酒店打集成战略然后睡觉,爽。晚上一块吃必胜客,爽。买蜜雪冰城,爽。回酒店大家都在打农,我不会,不爽。只能打 ABC,A 题吃一发,不爽。哦后面怎么这么简单,切完 F 开摆,爽。和 zibenlun 一起打集成战略遇到胡局了,爽。AT 上分了,爽。跟 Iceturky 和 zbl 开了歌回,爽。诶怎么就十一点了,睡觉了。

Day.2(3.2)

进场,发现屏幕被锁了,遂出场跟 chb 和黑塔聊天。诶怎么又解锁了,遂重新进场,开题。

听说 D2T1 会很难,让我看看。先按 $t$ 排序再说。诶这东西怎么这么熟悉,这不是 ABC371F 吗,我还写题解给学弟讲过,当时是用 set 写的,代码短但是细节多,不管了开写。写完之后发现 RE 在输入部分了,晕,看了半个多小时发现是 set 的指针在修改 set 后又使用了,这个好像是 UB,当时 HB 发的注意事项里有来着,调了调就过了。

哇怎么才一个半小时,这不赢麻了。看后面的题,哇怎么这么困难,先写暴力。写了两个小时终于战胜 $24+8$,看看还有啥性质,怎么这么多我哪个都不会。话说 T3 下一部分怎么答案这么小,暴搜是不是有前途,把原来的 set 改成手写哈希表试试,结果 6 秒变成 5.9 秒,还是过不了,最终 $100+24+8=132$ 遗憾离场了。

出场发现好多 $132$,这就是大众分吗。雪怎么下这么大,直接上车走了。车上先听说 unordered_set 就能跑过大部分,怄火。但是 chb 说我应该能进 D,希望吧,反正三场全是大众分还有可能挂,不好说。

路上很堵,两个半小时只走了二十公里,直接就近去济南东站坐火车了。回潍坊的都买了五点的票,但我只能买到七点的,又延误了一会,九点才坐上车,因此这篇游记大部分是在济南东候车时写的,到家已经十一点了。

啃啮土石摘雾凇,动静随心意。

循诵古训祝亲族,言语定心神。

总之我认真打的第一场省选就这么结束了,虽然有点不甘心,但至少比去年总分 $80$ 好,也没什么遗憾。感觉可能能混个 D 类,还是希望别挂分吧。

之后可能会先学点文化课,但我不太想把 OI 完全扔下,毕竟明年还要打,后续也有省集 APIO SC 之类。还是看看学校里怎么安排吧,教练还说会给找老师来着。总之先相信再相信,一切都会好的。

指木问路无回音,山岩自伫立。

径道错综归何处,问树树不知。

共 137 篇博客