Logo KSCD_ 的博客

博客

标签
暂无

P8257 题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-09-18 21:44:59

核桃周赛搬的,已严肃学习 hhoppitree 题解做法,记录一下。

题意

给定序列 $a$,$q$ 次询问 $[L,R]$ 内所有子区间权值异或和,区间权值定义为该区间内数字种类数。$n,q\le 4\times 10^5$,时间限制 $10$ 秒。

题解

询问所有子区间考虑离线,按照右端点排序后扫描,并维护每个点到当前点的种类数 $c_i$。扫到询问右端点 $R$ 时,$[L,R]$ 的区间历史异或和即为答案。然而历史异或和还是太难了,考虑避免历史和。注意到若 $t$ 时刻 $c_i$ 未修改,则 $t-1,t$ 两时刻的 $c_i$ 相等,异或后会抵消掉。因此从后往前每两个时刻一起算,则 $t-1,t$ 会贡献当且仅当 $ c_i$ 在 $t$ 时刻被修改,贡献值为 $c_{i,t-1}\oplus(c_{i,t-1}+1)$。

将该贡献放到 $t$ 时刻上,则历史和变成了奇偶性相同的若干时刻异或和。因此设 $b_{i,0/1}$ 表示目前 $i$ 处所有偶数 / 奇数时刻的总贡献,$t$ 时刻修改即区间内 $b_{i,t\bmod 2}$ 异或上 $c_i\oplus(c_i+1)$,之后 $c_i$ 加一;查询即求区间 $b_{i,R\bmod 2}$ 的异或和,这样就没有历史和了。

注意到 $c_i\oplus(c_i+1)$ 的值只与 $c_i$ 末尾 $1$ 的个数 $k$ 有关,该值为 $2^{k+1}-1$,因此大部分贡献值都很小。考虑根号分治,以 $2^B$ 为界划分,则当且仅当 $c_i$ 后 $B$ 位均为 $1$ 时贡献值会超过 $2^B-1$,而这每加 $2^B$ 才会发生一次,每个位置只会发生 $\frac n{2^B}$ 次,在 $B$ 足够大时即可暴力修改。

因此现在只需快速维护 $b$ 数组后 $B$ 位的值。考虑对原序列每 $S$ 个元素分一块,修改时对整块打标记并整体改动,散块下传标记后暴力修改,查询也是类似的,问题在于如何支持整体改。由于只考虑后 $B$ 位,可对每个块预处理出 $w_{i,v}$,表示 $i$ 块在 $tag\bmod 2^B=v$ 时再操作一次对后 $B$ 位的贡献。对该贡献拆位,则当且仅当 $(c_i+v)$ 的后 $j$ 位均为 $1$ 时会产生 $2^j$ 的贡献,此时 $(c_i+v)\bmod 2^j=2^j-1$,即 $c_i$ 与 $v$ 后 $j$ 位互为补集。

考虑从低位到高位对所有 $c_i$ 后 $B$ 位建立 Trie 树,求 $w_{i,v}$ 时在 Trie 树上找到 $2^B-1-(v\bmod 2^B)$ 这条路径,则其第 $j$ 层节点子树内均满足后 $j$ 位与 $v$ 互为补集,这些 $(c_i+v)$ 会产生 $2^j$ 贡献,因此当且仅当该子树大小为奇数时 $2^j$ 位为 $1$。由于只关心子树大小,可预先建出树,$c_i$ 直接贡献到叶子节点,之后遍历整棵 Trie 即可求出所有 $w_{i,v}$,时间复杂度单次 $O(2^B)$。整块修改时即可直接将值异或上 $w_{i,tag_i}$,再将 $tag_i$ 加一。

另外需支持迅速找到整块内目前 $c_i+tag\equiv {2^B-1}\pmod {2^B}$ 的所有位置,从而暴力更新高位信息。这需要在构建块时将所有 $c_i$ 按照 $c_i\bmod 2^B$ 排序,并记录每种值的区间,可以使用桶排。这样修改时只需要找到 $2^B-1-(tag\bmod 2^B)$ 对应的区间,暴力修改其中所有位置即可。要注意这种修改不能影响到后 $B$ 位,后 $B$ 位的贡献是单独计算的。这样整个重构操作就做完了,单次复杂度 $O(2^B+S)$,常数比较大。

还需要解决标记下传问题,$c_i$ 的更新是简单的,然而还需要更新所有 $b$ 的值。考虑同样拆位算贡献,对所有 $v\lt 2^B$ 记录下该块在 $tag=v$ 情况下操作次数的奇偶性。下传时将所有奇数次的 $v$ 放到 Trie 上,再查询 $2^B-1-(c_i\bmod 2^B)$ 即可,单次复杂度同样是 $O(2^B+S)$。

分析出来总复杂度为 $O(\frac{n^2}{2^B}+(n+q)(S+2^B+\frac {n^2}S))$,取 $2^B\pprox S=\sqrt n$ 可以得到理论最优复杂度 $O((n+q)\sqrt n)$。然而其中 $2^B$ 常数极大,实践发现取 $B=7,2^B=128$ 跑得最快。另外 $S$ 与 $B$ 是独立的,但实践下来发现同样取 $S=128$ 还是比较优的,因此下面的代码取了该块长。

代码

#include<iostream>
#include<vector>
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int N=4e5+10;
const int B=128;
const int M=B+10;
const int K=N\/B+10;
int n,m,a[N],res[N],last[N],lp[N],lg[M],tp[M],id[N],L[K],R[K],c[N];
int tag[K],b[2][N],s[2][K],w[K][M],fp[K][M],po[K][M],g[2][M<<1];
bool t[K][2][M],ct[M<<1]; \/\/ t 也是标记,记录每个块每种值操作次数的奇偶性 
vector <pii> ask[N];
void build(int u,int d,int x)
{
	if((1<<d)==B) {tp[x]=u; return;}
	lg[u]=d,build(u<<1,d+1,x),build(u<<1|1,d+1,x|(1<<d));
} \/\/ 建出 B 位的 Trie,并预处理每种值的位置 tp_x 
void built(int id)
{
	s[0][id]=s[1][id]=0;
	for(int i=0;i<=B;i++)
	{
		w[id][i]=fp[id][i]=0;
		for(int o=0;o<2;o++) t[id][o][i]=0;
	} \/\/ 清空原信息 
	for(int i=0;i<(B<<1);i++) ct[i]=0;
	for(int i=L[id];i<=R[id];i++)
	{
		s[0][id]^=b[0][i],s[1][id]^=b[1][i];
		ct[tp[c[i]&(B-1)]]^=1,fp[id][B-1-(c[i]&(B-1))]++;
	}
	for(int i=1;i<=B;i++) fp[id][i]+=fp[id][i-1];
	for(int i=L[id];i<=R[id];i++) po[id][--fp[id][B-1-(c[i]&(B-1))]]=i; \/\/类似桶排用 po 按值排序记录所有位置,fp 记录每种值的左端点 
	for(int i=B-1;i;i--) ct[i]=(ct[i<<1]^ct[i<<1|1]);
	g[0][1]=ct[1];
	for(int i=2;i<(B<<1);i++)
	{
		g[0][i]=g[0][i>>1];
		if(i<B) g[0][i]|=(ct[i]<<lg[i]);
	}
	for(int i=0;i<B;i++) w[id][i]=g[0][tp[B-1-(i&(B-1))]]; \/\/ 用 Trie 计算贡献数组 w  
}
void push(int id)
{
	for(int o=0;o<2;o++)
	{
		for(int i=0;i<(B<<1);i++) ct[i]=0;
		for(int i=0;i<B;i++) ct[tp[i]]^=t[id][o][i];
		for(int i=B-1;i;i--) ct[i]=(ct[i<<1]^ct[i<<1|1]);
		g[o][1]=ct[1];
		for(int i=2;i<(B<<1);i++)
		{
			g[o][i]=g[o][i>>1];
			if(i<B) g[o][i]|=(ct[i]<<lg[i]);
		}
	}
	for(int i=L[id];i<=R[id];i++)
	{
		for(int o=0;o<2;o++) b[o][i]^=g[o][tp[B-1-(c[i]&(B-1))]];
		c[i]+=tag[id];
	} \/\/ 同样用 Trie 进行 c 值的更新 
	tag[id]=0;
}
void pt(int o,int id)
{
	int v=(tag[id]&(B-1)); tag[id]++;
	s[o][id]^=w[id][v],t[id][o][v]^=1;
	for(int i=fp[id][v];i<fp[id][v+1];i++)
	{
		int p=po[id][i],d=((c[p]+tag[id])^(c[p]+tag[id]-1)^(B-1));
		s[o][id]^=d,b[o][p]^=d;
	}  \/\/ 暴力操作对高位产生影响的位置 
} \/\/ 操作一个整块 
void update(int o,int l,int r)
{
	int pl=id[l],pr=id[r];
	if(pl==pr)
	{
		push(pl);
		for(int i=l;i<=r;i++) c[i]++,b[o][i]^=c[i]^(c[i]-1);
		built(pl);
	}
	else
	{
		push(pl),push(pr);
		for(int i=l;i<=R[pl];i++) c[i]++,b[o][i]^=c[i]^(c[i]-1);
		for(int i=L[pr];i<=r;i++) c[i]++,b[o][i]^=c[i]^(c[i]-1);
		for(int i=pl+1;i<pr;i++) pt(o,i);
		built(pl),built(pr);
	}
}
int query(int o,int l,int r)
{
	int tr=0,pl=id[l],pr=id[r];
	if(pl==pr)
	{
		push(pl),built(pl);
		for(int i=l;i<=r;i++) tr^=b[o][i];
	}
	else
	{
		push(pl),push(pr),built(pl),built(pr);
		for(int i=l;i<=R[pl];i++) tr^=b[o][i];
		for(int i=L[pr];i<=r;i++) tr^=b[o][i];
		for(int i=pl+1;i<pr;i++) tr^=s[o][i];
	}
	return tr;
}
int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m,build(1,0,0);
	for(int i=1;i<=n;i++) cin>>a[i],lp[i]=last[a[i]]+1,last[a[i]]=i,id[i]=(i-1)\/B+1,R[id[i]]=i;
	for(int i=n;i;i--) L[id[i]]=i;
	for(int i=1,l,r;i<=m;i++) cin>>l>>r,ask[r].pb({l,i});
	for(int i=1;i<=n;i++)
	{
		update(i&1,lp[i],i);
		for(pii te:ask[i]) res[te.se]=query(i&1,te.fi,i);
	}
	for(int i=1;i<=m;i++) cout<<res[i]<<'\n';
	return 0;
}

【学习记录】凸优化

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

之前看到 KingPowers 的专栏准备学来着,但一直鸽到现在,且目前只做了极少的例题,之后陆续更新。

大部分借鉴自 凸优化常见技巧 做题笔记 By KingPowers 和 从带权二分到闵可夫斯基和与凸生成函数 By 绝帆,拜谢拜谢拜谢。

带权二分(wqs 二分)

一般求解限制某个量恰为 $x$ 的最值问题,设 $f(x)$ 表示该问题的答案,首先要求 $f(x)$ 关于 $x$ 是上凸 / 下凸的。验证凸性可以使用感性理解、打表、费用流等方式。

由于 $f(x)$ 是凸的,用斜率为 $k$ 的直线去切该凸包时,切到的点随着 $k$ 的变化是单调的。因此可以二分斜率 $k$ 去切凸包,并求出切到的点,最终切到 $(x,f(x))$ 点即可求出答案。

为了避免细节讨论,在切到一条线时可以求其中 $x$ 最小的点,二分出的也是能切到且不超过 $x$ 的最大横坐标,答案同样是求出的截距 $b$ 加上 $x\times k$。

在使用时若 $f(x)$ 均为整数,只需要对整数斜率二分,这是因为此时所有的斜率均为整数。若 $f(x)$ 是实数则需要使用实数二分。

P2619 [国家集训队] Tree I

题目链接提交记录

题意

给定 $n$ 点 $m$ 边的图,边有边权和黑白颜色,求其恰好包含 $x$ 条白边的最小生成树。$n\le 5\times 10^4,m\le 10^5$。

题解

这题比较板,也是笔者第一道 wqs 二分题。

直接根据上述过程做,设 $f(x)$ 表示 $x$ 条白边的最小答案,感性理解其是下凸的。之后直接二分斜率 $k$,求出截距 $f(x)-kx$ 的最小值及对应的最小 $x$,方式为将白边的边权减去 $x$,跑 Kruskal 时若边权相同则优先取黑边。

这样就做完了,复杂度 $O(m\log m\log V)$,当然也可以提前对两种边分别排序,check 时归并起来,复杂度 $O(m\lpha(m)\log V)$。凸性证明是困难的,略过不表。

HT-065-NOI T2 生成树

题目链接题解

本题 $50$ 分的做法与上题相同,然而后半部分运用性质消掉了一层枚举,从而降低了复杂度。关键在于注意到多轮 wqs 二分本质相同,从而直接用一轮二分代替,下一题也有同样的优化思路。这是笔者第二道 wqs 二分题

ARC168E Subsegments with Large Sums

题目链接提交记录提交记录'

题意

给定长为 $n$ 的正整数序列 $a$,要求将其分成 $x$ 段,求总和不小于 $s$ 的段数最大值。$1\le x\le n\le 2.5\times 10^5,1\le a_i\le 10^9$。

题解

首先显然有 $O(n^3)$ 的暴力 DP,然后就发现答案关于 $x$ 不是凸的,因此不能直接上 wqs 二分。先抛开这个不谈,发现本题的答案本身就具有单调性,可以直接先套一层二分答案 $mid$,转化为求需要 $mid$ 段不小于 $s$ 时,最多能划分成多少段。

设这个值为 $f(mid)$,感性理解 $f(mid)$ 关于 $mid$ 是上凸的,比如 $mid=0$ 时可划分成 $n$ 段,$mid=1$ 时选择最短的合法区间合成一段,之后令合法段数增多需要减小的值不降。

因此可以使用 wqs 二分求出 $f(mid)$,对于斜率 $k$ check 时需要最大化划分的收益,其中总和不小于 $s$ 的段收益为 $1-k$,其余段收益为 $1$,要求在最大化收益的前提下最小化收益为 $1-k$ 的段数。该过程可以 DP 解决,设 $f_i$ 表示前 $i$ 个数划分的最大收益和对应最小段数,则 $f_i$ 可从 $f_{i-1}$ 和 $f_{p_i}$ 转移过来,其中 $p_i$ 表示最大的 $j$ 使得 $[j+1,i]$ 的区间和不小于 $s$,复杂度为 $O(n)$。

这样有两层二分,总复杂度为 $O(n\log^2n)$,已经可以通过本题。然而还是很有优化空间的,因为凸包上也是一个前缀的 $mid$ 合法。考虑对于整个凸包直接 wqs 二分,找到切到的最大合法点,之后向后扫过共线的所有点,找到最大的合法点即可。将其对 $k$ 取最小值即为答案,时间复杂度 $O(n\log n)$。

题解区的绝大多数题解似乎是以 $r-l$ 为区间代价再最小化,与上面的做法是本质相同的。

闵可夫斯基和

如上图,绿色凸包是红色和蓝色凸包做闵可夫斯基和的结果。

把边看作向量,可以发现原来两个凸包中每个向量均在新凸包中出现恰好一次。又由于凸包上的边按斜率单调排序,因此这样合并两个凸包的所有边即可,归并可以做到关于边数线性。

合并上 / 下凸包的操作是相同的,此时若有两个下凸包 $f,g$,它们的差分数组都是单增的,求其闵可夫斯基和时只需要将两个差分数组归并起来再前缀和回去即可。写出式子发现新凸包的 $h_i=\min_{j+k=i}(f_j+g_k)$,也就是用线性时间实现了两个凸包的 $(\min,+)$ 卷积,这可以对 DP 等进行优化。

Gym103202L Forged in the Barrens

题目链接提交记录

题意

给定长为 $n$ 的序列 $a$,要求将其划分为 $k$ 部分,每部分的价值为其段内极差,对所有 $k\in[1,n]$ 求最大价值和。$n\le 2\times 10^5,1\le a_i\le 10^9$。

题解

考虑暴力 DP,设 $f_{i,j}$ 表示前 $i$ 个数划分成 $j$ 段的最大价值和,时间复杂度 $O(n^3)$。由于极差是最大值与最小值的差,然而取不到最值一定不优,因此直接扔掉最值限制,改为每部分任选两个数作差,得到的答案不变。这样可以设 $f_{i,j,0/1,0/1}$ 表示第 $i$ 个数划分到第 $j$ 段,且是否已有减数 / 被减数的最大价值和,时间复杂度 $O(n^2)$。

然后优化不动了,但打表可以发现 $f_{n,k}$ 关于 $k$ 是凸的。凸的序列 DP 可以改成区间 DP 的形式,再用闵可夫斯基和优化合并,从而降低时间复杂度。对于本题,设 $f_{l,r,0/1/2,0/1/2,i}$ 表示 $[l,r]$ 区间内分成 $i$ 段,且第一段和最后一段分别无贡献 / 有减数 / 有被减数的最大收益。转移时可任取 $mid\in[l,r)$,有转移式: $$ f_{l,r,sl,sr,i}=\max \begin{cases} \max(f_{l,mid,sl,sr,k},f_{mid+1,r,sl,sr,k})\ \max_{x+y=i}(f_{l,mid,sl,0,x}+f_{mid+1,r,0,sr,y})\ \max_{x+y+1=i}(f_{l,mid,sl,1,x}+f_{mid+1,r,2,sr,y})\ \max_{x+y+1=i}(f_{l,mid,sl,2,x}+f_{mid+1,r,1,sr,y}) \end{cases} $$ 后三个式子直接把两边拿出来做 $(\max,+)$ 卷积即可,用归并实现闵可夫斯基和可做到区间长度的复杂度。

由于只需要求 $f_{1,n,0,0}$ 的所有值,每次直接取 $mid=\lfloor\frac {l+r}2 \rfloor$ 即可,会形成一个分治结构,总长度是 $O(n\log n)$ 的,因此总复杂度也是 $O(n\log n)$ 的,然而在本题要乘上大概 $3^3=27$ 的常数。

P11459 [USACO24DEC] It's Mooin' Time P

题目链接提交记录

题意

给出一个 01 串,单点修改 $i$ 位置的字符需要花费 $c_i$ 的代价,有且仅有首位为 1 且长为 $L$ 的串为好串。对 $[1,\lfloor\frac n L\rfloor]$ 内所有 $k$ 分别求使原串有至少 $k$ 个好串的最小代价。$n\le 3\times 10^5,L\le 3,c_i\le 10^8$。

题解

打表注意到答案关于 $k$ 是下凸的,于是仍然套用上题做法分治,设 $f_{l,r,x,y,k}$ 表示 $[l,r]$ 区间包含了 $k$ 个好串,且两边各有 $x,y$ 个 0 的最小花费。这里 $x,y\lt L$ 即可表示所有状态。转移时若 $L=2$ 则 $ly=0,rx=1$ 可多一个,若 $L=3$ 则 $ly=0,rx=2$ 或 $ly=1,rx\ge1$ 可多一个,其余段数不变。

精细实现可以做到每次合并只做 $L$ 次闵可夫斯基和。同时为了减小常数和避免细节,在区间长度低于 $O(L)$ 时直接暴力枚举所有情况计入状态即可。总时间复杂度 $O(2^L\frac nL+n\log nL^2)$,后一项只有平方是因为每个区间的状态数为 $\frac {len} L$,可以约去一个 $L$。

slope trick

用于优化形如凸分段一次函数的 DP,这保证斜率单调,因此维护所有斜率变化的点,相同点的个数表示斜率变化量,这也要求斜率不能太大。

由于我还没怎么做所以概述之后再补

P4597 序列 sequence

题目链接提交记录

题意

给定长为 $n$ 的序列 $a$,每次操作可将某数增大或减小 $1$,求使其不降需要的最少操作次数。$n\le 5\times 10^5,-10^9\le a_i\le 10^9$。

题解

显然只会填原序列中有的数。因此可设 $f_{i,j}$ 表示填完前 $i$ 个数,第 $i$ 个数填 $j$ 的最小总次数。直接前缀优化转移即可做到 $O(n^2)$,因为数字种类数是 $O(n)$ 的。

把 DP 式写出来,设 $g_{i,j}=\min_{k=1}^j f_{i,k}$,则 $f_{i,j}=g_{i-1,j}+\left|j-a_i\right|$。$f_i,g_i$ 均是凸的分段一次函数,证明考虑初始的 $f,g$ 均是凸的,而下凸包加绝对值一次函数和向前取最小值后均保持凸性。

因此维护函数的拐点,由于一直会向前取最小值,这说明斜率为正的部分不造成贡献,因此可只维护斜率为负的拐点,并认为最后一个点之后斜率是 $0$。之后依次加入每个 $a_i$,此时找出最后一个拐点 $p$ 并分讨:

  • 若 $a_i\ge p$,则 $a_i$ 左边的部分斜率减小 $1$,右边斜率保持为 $0$,因此新加入一个拐点 $a_i$。
  • 否则 $a_i\lt p$,此时 $a_i$ 左边斜率减小 $1$,右边斜率增加 $1$,因此新加入两个拐点 $a_i$;$p$ 之后的斜率变为 $1$,这会被取最小值操作推平,因此删掉一个 $p$;同时 $p$ 处的值增大了 $p-a_i$ 且仍为最小值,因此给答案加上 $p-a_i$。

整个过程容易用优先队列维护,答案为最终 $p$ 处的取值,已经在过程中求出了,时间复杂度 $O(n\log n)$。

【听课记录】25.09-LCA-Week1

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

本来想只开一篇专栏,然而发现内容爆多,故决定之后每周开一篇记录。

09.24 排序分析

当只关心相对大小,而不关心实际值时,可将所有数离散化,得到值域为数字个数的新序列。

更进一步地,若只关心每个数与 $x$ 的相对大小,则可将其离散化为 $[a_i\ge x]$,得到一个 $01$ 序列,从而更容易分析其变化。

[AGC006D] Median Pyramid Hard

题意

给出一个长为 $2n-1$ 的排列,每轮依次取相邻三个并求中位数,得到长度减少 $2$ 的序列,如此进行 $(n-1)$ 轮,求最终得到的数。$n\le 10^5$。

题解

先二分答案,判断答案是否不小于 $x$,这时只关心数与 $x$ 的相对大小,因此只需对 $01$ 序列操作,判断最后剩下的数是否为 $1$。手推发现若有 $11$,则其可以一直向上延伸,直到某个位置消失,$00$ 也是类似的。同时若有 $101$,操作后 $0$ 上面是 $1$,因此 $11010$ 会变成 $110$,在边上仍然存在 $11$。

总结一下上述规律,发现离正中间最近的 $00$ 或 $11$ 会延伸得最高,之后与靠近中间的一侧不断合并,从而贡献到最顶端。同时由于序列长度是奇数,若两边最近距离相同,则它们的值也是相同的,两种值的最近距离一定不同。因此判断时找离中间最近的 $00$ 或 $11$ 即可,若无则说明整个序列是交替的,需特判为 $[a_1\ge x]$。时间复杂度 $O(n\log n)$。

考虑优化,发现只关心以每个 $x$ 为分界点时 $00$ 和 $11$ 到中间的最近距离。因此可以正序枚举 $x$,这时整个序列会从全 $1$ 逐渐变成全 $0$,容易维护每个时刻 $00$ 的最近距离。同理倒序枚举 $x$ 即可求得 $11$ 的最近距离,之后枚举答案并 check 即可,时间复杂度 $O(n)$,提交记录

P4375 [USACO18OPEN] Out of Sorts G

题意

给定序列 $a$,每轮先后进行顺逆冒泡排序各一次,求多少轮后序列不降。$n\le 10^5$。

Bonus:每轮进行顺序冒泡排序 $x$ 次,逆序冒泡排序 $y$ 次,原题为 $x=y=1$。

题解(Bonus)

先将原序列离散化,值相同的认为靠前的更小,这样能转化成一个排列。之后枚举每个值域分界点 $p\in[0,n]$,将原序列转化成 $b_i=[a_i\gt p]$ 的 $01$ 序列,则当且仅当所有 $01$ 序列均不降时原序列不降,因此对 $(n+1)$ 个 $01$ 序列的答案取最大值即可。

对于一个 $01$ 序列,手推可以发现顺序操作会将每个 $1$ 连续段的最后一个扔到下一个 $1$ 连续段开头,逆序是类似的。由于相同的 $01$ 值不作区分,可以认为顺序操作将第一个 $1$ 扔到结尾,逆序操作将最后一个 $0$ 扔到开头,求多少轮操作后 $0$ 是一段前缀。图形化的理解方式是从坐标系原点开始,经过 $0,1$ 时分别令 $x,y$ 增加 $1$,形成一段折线。关注折线下方的图形,则将 $1$ 扔到结尾会删掉最下面一行,将 $0$ 扔到开头会删掉最后一列,折线下方被删空时序列不降。

单轮操作只需要维护两个指针 $p,q$,初始 $p=0,q=n+1$,每轮 $p$ 向后扫过 $x$ 个 $1$,$q$ 向前扫过 $y$ 个 $0$,若 $p\gt q$ 则停止并返回当前轮数。考虑将这个过程形式化,设 $A_i$ 表示 $i$ 及之前 $1$ 的个数,$B_i$ 表示 $i$ 及之后 $0$ 的个数,则所求即 $\max_{i=0}^n\min(\lceil \frac {A_i}x\rceil,\lceil \frac{B_{i+1}}y\rceil)$,含义即为每对 $i\lt j,b_i=1,b_j=0$ 的 $(i,j)$ 均需要交换前后顺序,对它们需要的轮数取最大值。

此时从小到大枚举 $p$,每次只会将一个 $1$ 变成 $0$,这会对 $A$ 的一段后缀以及 $B$ 的一段前缀进行修改,两个树状数组即可维护。同时由于 $A$ 不降且 $B$ 不增,找到 $\lceil \frac {A_i}x\rceil\le\lceil \frac{B_{i+1}}y\rceil$ 的最后一个位置 $t$ 后,只需要对 $i=t$ 和 $i=t+1$ 取最大值即可。而修改是减少 $A$ 且增加 $B$,因此 $t$ 的位置也是不降的,每次更新后尝试向后移动 $t$ 即可,时间复杂度 $O(n\log n)$,提交记录

事实上,对于每个分界点 $p$ 来说,目标是令其前面全为 $0$,后面全为 $1$,因此在 $x=y$ 时(比如原题的 $x=y=1$),每次就会将 $p$ 前面的 $x$ 个 $1$ 扔到后面,之后将 $y=x$ 个 $0$ 扔回来,答案就是 $\lceil \frac {\max_{p} \sum_{i=1}^p [a_i>p]} x\rceil$。然而 $x\ne y$ 时进出不相等,比如 $y< x$ 时扔到后面 $x$ 个 $1$,然而递补过来的 $(x-y)$ 个值不确定,因此不能这么做。

09.24 思考题 区间排序

我说这才是排序分析

有一个长为 $n$ 的序列 $a$,给出操作 $s(l,r)$,表示对序列 $a$ 该区间升序排序,称一个排序过程合法当且仅当所有可能的序列 $a$ 在经过这些操作后均不降。

  • $a_i$ 的取值只要不唯一,排序过程合法性与值域无关。

对于同样的排序过程,序列合法本质上是 $O(n)$ 个 $01$ 串均合法,找到瓶颈所在的 $01$ 串即可构造出取值只有两种的等价序列。

  • 若限制 $r-l+1\le 2$,合法排序过程的最小步数量级为 $O(n^2)$。

显然每次最多只能减少一个逆序对,构造冒泡排序过程可以达到下界 $\frac{n(n-1)}2$。

  • 若限制 $r-l+1\le 3$,合法排序过程的最小步数?

每次最多减少 $3$ 个逆序对,因此有下界 $\lceil\frac{n(n-1)}6\rceil$,当然这个下界很可能是达不到的。同时严格优于限制为 $2$ 的情况,有上界 $\frac {n(n-1)}2$。直接用长为 $3$ 的区间构造冒泡排序可以做到大概 $\frac {n(n-1)}4$,因为可以将两个长为 $2$ 的操作合并成一个。

还有一种构造是每轮不重复地覆盖整个序列,从而让整个序列变得合法,LCA 课上提了一种做法,据说是 $\frac {2n(n-1)}9$ 的,然而写了程序爆搜 $9$ 以内的循环节并没有找到低于 $\frac {n(n-1)}3$ 的合法覆盖方式,先不管了。

  • 验证排序过程合法性时,只验证降序合法是否能直接说明合法?

是可以的,仍然考虑 $01$ 串,定义 $p$ 不劣于 $q$ 当且仅当两者长度相同,$1$ 的个数相同,且对于每个相同排名的 $1$,在 $p$ 里的位置均不比在 $q$ 里靠前。这个定义下并非任意两串都能分出优劣(比如 $0110$ 和 $1001$),但这是具有传递性的,且升序合法状态比其他串都不劣,降序串比其他串都劣。

更进一步地,每个串每次操作都不会变劣,且若 $p$ 不劣于 $q$,两者均经过某操作 $s(l,r)$ 后得到的 $p',q'$ 一定满足 $p'$ 不劣于 $q'$,证明只需要考虑两者该区间内 $1$ 的变化即可。由此无论操作序列如何,降序串一直是最劣的,因此降序串合法就能说明原串合法。再结合第一条即可说明该结论。

  • 哪些常见排序算法可以描述成上述区间排序过程?

冒泡排序,且满足 $r-l+1\le 2$。

插入排序,方式是依次进行 $i\in[1,n]$ 的所有 $l=1,r=i$。

归并排序,先递归到 $[l,mid],[mid+1,r]$,再进行 $s(l,r)$ 的归并过程。

[AGC001F] Wide Swap

题意

给出长为 $n$ 的排列 $p$,可进行任意次交换 $p_i,p_j$ 的操作,但必须满足 $\left|i-j\right|\ge k$ 且 $\left| p_i-p_j\right|=1$,求字典序最小的最终排列。$n\le 5\times 10^5$。

题解

有值限制的任意交换太困难了,考虑转化为逆排列 $q_{p_i}=i$,并在 $q$ 上进行交换。这时限制变为 $\left|q_i-q_j\right|\ge k$ 且 $\left| i-j\right|=1$,第二个限制就是相邻了,这样看起来就好了很多。同时字典序最小的 $p$ 对应的是倒序字典序最大的 $q$,证明考虑首先要让 $q_x=1$ 的 $x$ 尽可能小,也就是从小到大依次尽可能靠前,那么从后往前依次填尽可能大的数就是对的。

由于只能邻项交换,考虑初始序列 $q$ 和最终序列 $r$,若 $q$ 中 $x$ 在 $y$ 前面,$r$ 中 $x$ 在 $y$ 后面,则交换过程中一定直接交换过 $x,y$ 两个值,因此要求 $\left|x-y\right|\ge k$。每一对值均有该限制,存在限制无法满足的最终序列一定操作不出来。

若能证明满足限制的最终序列 $r$ 一定能操作出来,那么就可以这样刻画合法序列。考虑构造 $q$ 变成 $r$ 的操作,方式是依次将 $q$ 的每一位变成与 $r$ 相同,若目前不同则从后面依次交换过来,然后忽略第一位继续向后构造。若过程中出现无法交换的情况,此时这两个值的先后顺序一定需发生变化,这说明 $r$ 无法满足该限制,而这是不可能发生的。因此一定能构造出 $r$。

将该限制重写回 $p$,则对于所有 $\left|i-j\right|\lt k$ 的下标 $i,j$,若初始时 $p_i<p_j$,则最终也一定有 $p_i\lt p_j$,求字典序最小的 $p$。这是一些偏序限制,然而解决方式并非由 $i$ 向 $j$ 连边,再进行取最小值的拓扑;而是应该建反向边,并进行取最大值的拓扑,并依次为其赋上从大到小的值。比如 $n=3$ 时只有 $(3,1)$ 的限制就能卡掉。然而本题的边比较特殊,错误方式也能过。

这样我们得到了 $O(n^2)$ 的拓扑排序做法,优化可以使用线段树隐式建图,考虑 $i$ 的入度为零表现为只考虑未处理的点时,$i$ 在 $p$ 的 $(i-k,i+k)$ 区间内为最大值。因此用线段树维护该过程,用堆维护目前入度为 $0$ 的所有点,每次取出堆顶 $i$ 时只需要查看 $(i-k,i)$ 和 $(i,i+k)$ 两区间内是否有点入度变为 $0$ 即可。时间复杂度 $O(n\log n)$,提交记录

另一种考虑方式是类似前置,直接找到倒序字典序最大的 $q$,最后再转回原排列。考虑直接任取一个 $q_i-q_{i+1}\ge k$ 并将其交换,直到不存在这样的 $i$,并证明这样一定能操作到最优解。

设上述操作得到序列 $r$,若要继续操作使其更优,一定要进行 $q_i\lt q_{i+1}$ 的交换,且只有向前与最近的 $q_p\gt q_{i+1}$ 交换才会变得更优。然而此时 $q_{p+1}<q_{i+1}$,且 $q_p-q_{i+1}\ge k$,从而一定有 $q_p-q_{p+1}\ge k$,与前面的假设矛盾。因此无法操作的序列一定最优,同时最优解唯一,从而任选这样的位置操作均能得到最优解。

因此只进行 $q_i-q_{i+1}\ge k$ 的操作即可,同前置可用冒泡排序维护该过程,即每次从头到尾试图进行合法操作,从而确定 $r_n$ 的值,再对前 $n-1$ 个数进行操作。容易分析出这样放到结尾的一定是能到结尾的最大值,时间复杂度 $O(n^2)$。

优化考虑前置中区间排序状物的排序算法,其中只有归并排序是 $O(n\log n)$ 的,因此尝试用归并排序代替冒泡排序,每次将左右两边归并起来,从后往前确定值。此时右边可以直接放,左边的 $x$ 要放必须越过右边未放的所有元素。

该限制看似困难,然而只要右边还有比 $x$ 大的数 $y$,此时就一定不会放 $x$,同上面的证明过程,$x$ 跳过 $y$ 后只有再跳过比 $x$ 小的元素才能更优,然而这不可能存在,否则右边还能操作。综上 $x$ 只在比剩余最大值 $y$ 大时会被放,且需满足 $x-k\ge y$,预处理右边前缀最大值即可快速查询 $y$。总时间复杂度 $O(n\log n)$,常数比上种做法小得多,提交记录

09.26 括号序列

其实不止是括号序列,一些类似匹配消除的序列也可以归入此类。

P9753 消消乐

参见【做题记录】P9753 + CF1223F,有补充,此处略过不表。

P7323 [WC2021] 括号路径

题意

给出一张 $n$ 个点 $2m$ 条边的有向图,输入的 $m$ 组 $(u,v,w)$ 同时表示 $(u,v,w)$ 和 $(v,u,-w)$ 两条边,正负分别表示该种的左右括号。求有多少组 $x\lt y$ 满足存在一条边权为合法括号序列的从 $x$ 到 $y$ 的路径。$n\le 3\times 10^5,m\le 6\times 10^5$。

题解

注意到合法性是可以传递的,即 $(x,y)$ 和 $(y,z)$ 均合法即有 $(x,z)$ 合法,这对应合法括号序列的拼接。同时合法性是对称的,即若 $(x,y)$ 间存在合法路径,走它们的反向边即为 $(y,x)$ 间的合法路径。于是可以对所有点划分集合,使得每个集合内两两间均有合法路径,答案即 $\sum {c\choose 2}$。

可以使用并查集维护集合,上述拼接的合并是自然的,还需要实现在外面套一层括号的合并,这需要对每个集合维护所有入边,并在合并集合时将相同种类入边起点合并起来。用 map + 启发式合并可以做到常数不大的 $O(m\log ^2m)$,用线段树合并可以做到 $O(m\log k)$,后者跑得快一些。

P11236 [KTSC 2024 R1] 水果游戏

题意

给定序列 $a$,操作可以将序列中相邻相等的两个 $x$ 替换为一个 $x+1$。要求支持单点修改,查询某区间任意操作后最大值的最大值。$n,q\le 10^5,a_i,x\le 10$。

题解

先考虑不带修的情况,虽然这和正解没啥关系。可以想到只关注那些能合成单个数的区间 $(l,r,x)$,区间询问时找该区间完全包含的 $x$ 最大值即可。现在需要说明这样的区间个数有限,并找出所有的这类区间。将其转化为 $b_i=2^{a_i}$,则区间能合成单个数需要能分成两个和为 $2^{k-1}$ 的合法区间。

显然有数量上界 $O(nV)$,固定左端点即可。预处理可以倒着扫,每次二分出对应的右端点 $r$ 和中点 $m$,还要求 $m$ 开始的 $2^{k-1}$ 合法,复杂度容易做到 $O(nV\log n)$,用双指针可能也能做到 $O(nV)$。对区间贡献容易矩形加扫描线,强制在线也能可持久化,反正能做,时间复杂度 $O(nV\log n)$。

事实上即使没有值域限制,也有数量上界 $O(n\log n)$,虽然这和正解也没关系。考虑分治,每次取中点 $mid$,只考虑 $l\le mid\lt r$ 的所有区间。枚举较长一侧的长度,则只有唯一的 $2^k$ 与之对应,同时总共只有 $O(n\log n)$ 的枚举量,因此合法区间数量至多是 $O(n\log n)$ 级别的。

再考虑带修情况,然后发现上面的东西根本拓展不了,需要其他性质。考虑合并过程中若出现 $x_i\lt x_{i-1},x_{i+1}$,则 $x_i$ 之后无法再合并,可将其删去并将序列分成两半。同样地,将 $y$ 个 $x$ 的相等连续段缩成 $(x,y)$ 后再考虑,若有 $x_i\lt x_{i-1},x_{i+1}$,讨论是否有 $2^{\min(x_{i-1},x_{i+1})}\mid y$,若有则将其强制合并成较小的,贡献到对应的 $y$ 里并将其删去;否则其同样无法被跨过,然而此时还可能分别向两边贡献,可改为 $(x,y),(\infin,0),(x,y)$ 三个元素,使其能向两边贡献。

注意到序列不能再缩时能以 $\infin$ 为分界线分成若干单峰序列,每部分之间独立,且只有两边的序列会改变。这可以作为区间信息维护到线段树上,从而支持单点修改和区间查询。需要维护的有区间能合成的最大值 $w$,区间是否只有一个单峰序列以及左右两侧的单峰序列。

合并时 $w$ 先对两儿子取较大值,再将中间的两个单峰序列合并,并将新序列能形成的最大值贡献给 $w$。合并方式是依次将右边的 $(x,y)$ 放到左边结尾,先不断进行删除操作直到结尾 $x_i\ge x$,再将其贡献到 $y_i$ 或直接加入,左序列单增时也可以直接加入。统计能合成的最大值只需要从两边依次贡献到中间即可。细节较多,单次合并的复杂度为 $O(v)$,总时间复杂度 $O((n+q)v\log n)$,空间复杂度 $O(nv)$,可以通过。

CF1685C Bring Balance

题意

给出一个左右括号各 $n$ 个的序列,操作可选择区间按下标翻转,求使该序列平衡的最小操作次数,构造方案。$\sum n\le 2\times 10^5$。

题解

扔到折线上考虑,观察区间翻转会造成什么影响,发现是折线中心对称,即 $\forall i\in[l-1,r],a'i=a{l-1}+a_r-a_{l-1+r-i}$。因此感性理解会选择尽可能大的 $a_{l-1},a_r$,考虑全局最大值 $a_p$,若选择 $[1,p]$ 和 $[p+1,r]$ 两次操作,每个元素都会变成 $a_p-a_t\ge 0$,序列必定合法,所以操作次数不超过 $2$。

操作次数为 $0$ 容易判断。而操作次数为 $1$ 只能操作一次,又必须覆盖所有初始为负的位置。设最靠前的负位置为 $x$,最靠后的负位置为 $y$,则取 $x$ 之前的前缀最大值和 $y$ 之后的后缀最大值操作一定最优,检查是否能让所有负位置变为非负即可。复杂度 $O(n)$。

CF1458D Flip and Reverse

题意

给出一个 01 串,每次操作可选择一个 01 数量相等的区间,将其先按值取反再按下标翻转,求任意操作后能得到的字典序最小串。$\sum n\le 5\times 10^5$。

题解

仍然扔到折线上,操作相当于折线左右对称。观察考虑后发现这不会改变值上的连边情况,即每种 $(a_i,a_{i+1})$ 都是不变的。另外若用相同 $(a_i,a_{i+1})$ 构造折线,则一定能用题目操作得到。于是就变成安排边的顺序,使得字典序最小。

记录每种边的数量,直接求字典序最小的欧拉路径即可。然而这题的边很特殊,可以用贪心求。具体地,边的方向甚至都不重要,只要安排了对应数量的边,最终方向也一定是对的。因此每次看是否能到 $x-1$,若存在 $(x-1,x)$ 且 $(x,x+1)$ 不存在或 $(x-1,x)$ 有超过一条,就可以直接走到 $x-1$,否则走到 $x+1$。时间复杂度 $O(n)$。

CF1503F Balance the Cards

大概是推一推结论之后建模成平面图上将某个结构缩成单点,维护这个过程求解。太困难遂弃之。

彩色括号?

题意

给出一个括号序列,有红绿蓝三种颜色,可进行单点修改操作,要求最终红绿和绿蓝子序列均为合法括号序列,求最小操作次数。$n\le 5000$,Bonus:$n\le 10^5$。似乎没有出处。

题解

考虑对单个序列如何令其合法,发现只会修改最前的右括号和最后的左括号,且一定是单个修改同种若干次,再修改若干对括号,这是因为要求前缀和非负,而这种修改得到的前缀和最大。

然而三色括号很难处理,考虑通过枚举某些量的方式简化,注意到绿色在两边都有,若枚举绿色的单个修改情况,就可以推出其他两种颜色的单个修改情况,并根据上述结论得到一个新序列,满足红绿和绿蓝子序列中的左右括号数量平衡。之后再枚举绿色修改的括号对数 $c$,同样也是从两边开始修改,之后需要用红蓝两色的成对修改使得两串合法,显然 $c$ 递增时两边需要的修改数均不降,可以使用双指针维护两边需要的次数。枚举量是 $O(n^2)$ 的,细节实现没想好。

Bonus 应该是减少一维枚举,但没想。

09.26 思考题 介值定理

介值定理表明,闭区间上的连续函数可以取到最大值和最小值之间的任意值。

在 OI 中,单次变化量为 $1$ 的函数可以认为是连续的,一定能取到最大值和最小值之间的任意整数值。OI 中运用时可以使用二分,注意这里不需要单调性,只要时刻保证 $f(l)$ 和 $f(r)$ 在所求值 $y$ 两侧即可。

应用上比如说要求 $g(x)\times g(x+1)<0$ 的某个位置,可以通过某种方式求出 $g$ 的全局最大值和最小值,若异号则一定存在某个位置两侧的符号不同,二分并时刻保证左右端点不相同即可。可参见 25.02-MX-D3T1

有一些例子,比如给出若干根粗细相同,密度均匀但质量不同的棍,可以至多切两刀,再将其分成两个集合,要求同时均分体积和质量。考虑将其首尾相接拼成环,则环的任意直径都能均分体积,这时逐渐改变直径的角度,两侧的质量差会连续变化,且旋转 $180$ 度后质量差是原来的相反数,根据介值定理一定存在一个时刻均分质量,二分找到该时刻并从对应位置切开即可。

还有一种方式是将 $(v,m)$ 向量相加画在二维平面上,现要求其过 $(\frac v2,\frac m2)$ 点,从而该点两侧的集合满足限制。此时只要有相邻向量的平行四边形包含该点,就可以通过沿该点的投影切开两向量,再通过平移经过该点。由于按斜率升序和降序排序分别在该点上下两侧,因此不断邻项交换斜率逆序对,总存在一个时刻能包含该点,实现上可以二分冒泡排序的过程?反正这种题实现也不重要不管了

等分平面点集

给定二维平面内 $n$ 个点,其互不重合且三点不共线。所有问题中线上的点均可自由决定归属。

  • 对 $a,b,c$ 取遍任意实数的所有直线 $ax+by+c=0$,它们上方的点集种类数是什么级别的?

考虑对于所有直线,均向上平移直到碰到点,之后令其绕该点顺时针旋转,直到碰到另一个点。整个过程中上方点集没有改变,而最终找到了一条等价的过两点的直线。由于过两点的直线只有 $O(n^2)$ 条,本质不同的上方点集也不超过 $O(n^2) $ 种。

  • 给定点 $(x,y)$,从过该点的直线中找一条,使得其两侧的点数差不超过 $1$。

介值定理,两侧交换,差变为相反数,一定存在零点。

  • 找两条相交的直线,使得四个部分中的点数极差不超过 $1$。

先任取一条平分所有点的直线,再找一条与其相交的直线同时平分两部分。方式是考虑两条直线的夹角 $\theta$,再令其平分上方的点,此时下方的点数差随 $\theta$ 连续变化,这个画图分析一下线碰到点的时刻即可。由此根据介值定理即可确定出同时平分两部分的直线。

  • 找三条共点的直线,使得六个部分中的点数极差不超过 $1$。

先找到与横轴夹角为 $\theta_1$ 的平分所有点的直线,再用上面的方式找出同时将两部分划分为 $1:2$ 的直线,夹角为 $\theta_2$,最后再将其中一个 $2$ 平分,夹角为 $\theta_3$。可以说明此时另一个 $2$ 两侧的点数差随着 $\theta_1$ 的变化是连续变化的,且 $\theta_1$ 增大 $180$ 度时取相反数,因此同样可以根据介值定理确定解。

另外,更多条直线的情况就不能再这么做了,因为上面第三维用到了第一维的自由度,之后就没法确定了,总之比较抽象,但是思想值得学习。

9.28 序列相关

  • 区间最值

区间最值可用笛卡尔树刻画,$[l,r]$ 的区间最值为笛卡尔树上 $l,r$ 两点 LCA 的值。有时一类关于区间最值,尤其是最近的比自己大 / 小的位置有关的问题可以考虑笛卡尔树。

CF1748E Yet Another Array Counting Problem

题意

给出序列 $a$,求值域为 $[1,m]$,且所有子区间的最靠左最大值位置均与 $a$ 相同的序列 $b$ 数量。多组数据,取模,$\sum nm\le 10^6$。

题解

对序列建出大根笛卡尔树,子区间最靠左最大值位置即两端点 LCA,因此要求 $b$ 序列的笛卡尔树结构与 $a$ 相同。在 $a$ 的笛卡尔树上进行树形 DP,设 $f_{u,i}$ 表示 $u$ 点值为 $i$ 时子树内方案数,转移为 $f_{u,i}=(\sum_{j=1}^{i-1}f_{lc_u,j})(\sum_{j=1}^i f_{rc_u,j})$,用前缀和优化即可做到 $O(nm)$。

[ABC262Ex] Max Limited Sequence

题意

给出若干限制 $l,r,x$,表示要求 $a$ 序列的 $[l,r]$ 区间最大值为 $x$。求值域在 $[0,m]$ 内的合法 $a$ 序列数量。取模,$n,q\le 2\times 10^5,m\lt mod=998244353$。

题解

这是 LCA 所说没那么板的区间最值题。要求形如区间均不超过 $x$,且至少存在一个 $a_i=x$,此时每个位置都有一个最低下界 $b_i$,这可以随便用数据结构求出。之后再考虑区间存在 $x$ 的限制。注意到区间 $b_i\le x$,不存在超过 $x$ 的 $b_i$,因此只考虑 $b_i=x$ 的位置即可。

所以将位置按 $b_i$,限制按 $x$ 分类,对这些位置和限制一起算方案数,限制形如某些区间内至少有一个取到上界,不取到上界的 $x$ 种值是等价的。这就容易 DP 了,可设 $f_{i,j}$ 表示考虑完了前 $i$ 个位置,目前左端点在 $i$ 之前且仍未覆盖的右端点最大值为 $j$,转移形如前缀乘、后缀查和单点加,直接用线段树维护即可,时间复杂度 $O((n+q)\log n)$。

  • 区间连续段

在排列中的定义为 $\max-\min=r-l$ 的区间,感觉用处不大,可能有时会对连续段 DP。求区间连续段可以使用下述扫描线,复杂度 $O(n\log n)$,也存在析合树做法,不过 LCA 都说没啥用,不管了。

P8600 连号区间数

求排列的区间连续段数量。$n\le 5\times 10^4$,Bonus:$n\le 5\times 10^5$。考虑将条件移项,变为 $\max-\min-r+l=0$,同时有天然条件 $\max-\min-r+l\ge0$。

可以多次单调栈分别求出每个数左 / 右边第一个大于 / 小于其的位置,之后其作为最值的贡献矩形确定。$l,r$ 的贡献容易维护,直接上线段树扫描线,维护最小值及其个数,从而计算全局 $0$ 的个数即可。时间复杂度 $O(n\log n)$。

  • 排列

这里不研究排序分析和置换,主要研究排列相关的 DP 之类。

P8376 [APIO2022] 排列

题意

构造尽可能短的排列 $p$,使得其上升子序列个数恰为 $k$。$k\le 10^{18}$,要求构造出的长度 $n\le 90$。

题解

事实上属于构造题范畴,这种构造数值的问题一般要考虑怎么进行基础操作,比如加 $1$ 和乘 $2$ 之类,从而构造出任意值。比如本题中若已有个数为 $x$ 的排列,则在其结尾添最小值可得到 $x+1$,添最大值可得到 $2x$,这样从高位构造到低位即可做到不超过 $2\log_2k$ 的次数。

然而还需要更少,但乘 $2$ 已经是增多的极大值了,难以优化,考虑对加 $1$ 下手。注意到整个排列可以分成两个子序列,分别是加一的递减序列和乘二的递增序列。在该结构结尾添加序列次小值时,得到的是 $x+2$,同样添加第三小值可得 $x+3$。

由于有乘 $2$ 操作,加 $2$ 是没用的,而加 $3$ 可以一次添加两个 $1$,且最小值和次小值相对位置不变,仍然可以继续加 $3$,这样就可以在加三次 $1$ 后每两位使用至多 $3$ 个新元素处理。这样总次数的量级降到了 $1.5\log_2 n$,细致分析一下的话第一个加 $1$ 不需要操作,且乘 $2$ 次数本来就少 $1$,不会超过 $90$ 次,可以通过。

P5999 [CEOI 2016] kangaroo

题意

给定 $p_1$ 和 $p_n$,求有多少种这样的排列满足 $\forall i\in[2,n-1],[p_{i-1}<p_i]=[p_{i+1}<p_i]$。取模,$n\le 2000$。

题解

如果从左到右考虑,只能记录最后一个数在前面的相对排名,导致难以确定开头为 $s$。因此按值从小到大考虑,并维护当前连续段数量,注意除开头结尾的边界均应比内部低,从而之后合成一段。

因此设 $f_{i.j}$ 表示考虑了 $[1,i]$ 内的数,当前有 $j$ 个连续段的方案数,转移可以单开一段或合并两个段。对 $s,t$ 需要特判放在开头结尾,这表现为只能在固定位置新开一段,或直接接在对应段上。此处直接接上虽然不满足比内部小,但其实固定为边界就不用满足了。总复杂度 $O(n^2)$。

P9197 [JOI Open 2016] 摩天大楼 / Skyscraper

题意

给定序列 $a$,求 $\sum_{i=1}^{n-1} \left|a_{p_i}-a_{p_{i+1}}\right|\le L$ 的排列 $p$ 数量。取模,$n\le 100,L\le 1000$。

题解

同样从小到大考虑,这样可以拆贡献,把差的绝对值拆到值域上,每经过一个单位长度就产生大概两倍段数的贡献。此处端点不贡献,因此需要记录已有端点的个数。于是设 $f_{i,j,k,o}$ 表示考虑了前 $i$ 小的数,当前形成 $j$ 个连续段,目前贡献 $k$,且已有 $o$ 个端点的方案数。

转移时讨论接在某个段上 / 新开一段 / 合并两段三种情况即可,注意均不能对已确定端点的位置操作,有多处需要减去 $o$。细节此处略去,时间复杂度 $O(n^2L)$。

这两题均是维护连续段个数,并以插入方式转移。这类问题通常可以画出示意图,之后考虑每个状态会对转移造成影响的量,只记录这些从而简化状态。例如这两题按值考虑后只需关注横线下的段数,因此只考虑段数即可。

CF2066D2 Club of Young Aircraft Builders

题意

给出长为 $m$ 的序列 $a$,要求将其中的 $0$ 替换为 $[1,n]$ 内的任意数,要求 $n$ 出现 $c$ 次,且 $\forall i\in[1,m],\sum_{j\le i}[a_j\ge a_i]\le c$。多组数据,$n,c\le 100,\sum m\le 10^4$。

题解

这题其实不是排列,但思路跟上面的题有共同点。D1 中 $a$ 数组全 $0$,显然可以从大到小依次填数,每次都填在前 $c$ 个内即可。然而这做不了有限制的情况,需要换一种做法。多种尝试后发现可以变为从小到大填数,则 $1$ 一定要填在前 $c$ 个内,若填了 $j$ 个,则填 $2$ 时可忽略这些位置。这等价于一定要填在前 $(j+c)$ 内,以此类推。

这时根据上题中的思路,已填的个数是唯一影响转移的量,因此只记这个就行。设 $f_{i,j}$ 表示考虑了前 $i$ 种值,总共填了 $j$ 个数的方案数。转移时可在前 $(j+c)$ 个位置内填,且一定要填上限制该数的所有位置。枚举填的个数 $k$,剩余位置的方案容易用组合数计算。时间复杂度为 $O(nmc)$,可以通过。总之还是要找转移所需的量维护在状态内。

25.09-LCA-Week1-4 模拟赛题解

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-09-26 09:30:51

09.25

T1 被前导零挂到 $30$ 了,其他打得还行。

T4 的 DP 只保留有效状态,值得学习。T5 的数据结构可以练习码力,已严肃练习。

T4 学术竞赛

题意

有 $n$ 名参赛者和 $m$ 道题,每人每题的得分均在 $[0,k]$ 内。给出所有得分情况 $a_{i,j}$,问最少保留多少个 $a_{i,j}$ 能唯一确定出原来的排名,分数相同的按编号从小到大排序。$n\le 2\times 10^4,m,k\le 100$。

题解

先排出目标排名 $p$,之后设 $f_{i,j}$ 表示考虑了排名前 $i$ 的所有人,且 $p_i$ 的分数下界 $l_{p_i}=j$ 时,最多能删掉多少个数。状态数是 $O(nmk)$ 的,转移时考虑枚举当前的左端点 $l$ 和删的个数 $c$,若 $p_i$ 删掉 $c$ 个数后和可为 $l$,则可转移 $f_{i,l}\leftarrow\max_{j=l+ck+[p_{i-1}>p_i]}^{mk} f_{i-1,j}$,可预处理后缀最大值,转移复杂度为 $O(nm^2k)$。转移前还需求出 $g_{c,l}$ 表示能否删掉 $c$ 个数后恰为 $l$,这可以使用背包解决,总复杂度 $O(nm^3k)$ 或 $O(\frac{nm^3k}w)$,难以通过。

接着发掘本题的性质,发现 $l_i\le s_i\le r_i$,即删数后的取值区间一定包含原来的和。那么一定有 $s_{p_{i+1}}\le l_{p_i}\le s_{p_i}\le r_{p_i}\le s_{p_{i-1}}$,否则一定不满足限制。设 $t_i=s_{p_i}-s_{p_{i+1}}$,有 $l_{p_i}\in[s_{p_{i+1}},s_{p_i}],s_{p_i}-l_{p_i} \le t_i$。于是以 $t_i$ 为最大容量做背包,也只枚举 $t_i$ 种 $l$,后缀最大值也只取 $i-1$ 有意义的部分。这样单次背包复杂度为 $O(m^2 t_i)$,单次转移复杂度为 $O(mkt_i)$。由于 $\sum t_i=O(mk)$,总复杂度为 $O(m^3k+m^2k^2)$,可以通过。

原题

P13345

T5 lunatic 难度佩洛洛斯拉

题意

有一个两维大小均为 $n$,初值均为 $0$ 的数组 $a$,先进行 $n$ 次矩形 checkmax,再求 $m$ 次矩形和,保证修改的 $xl=1$ 或 $xr=n$。$v\le n\le 10^6,m\le 5\times 10^5$,时间限制 $16$ 秒。

题解

考虑保证全部 $xl=1$ 怎么做,由于只有前缀操作,此时每一行元素均不降。因此从右往左扫描线,扫到修改右边界时区间 checkmax,查询差分成两个后缀,在对应时刻查询历史和。全部 $xr=n$ 的情况是类似的,此时每行元素不增。

两种都存在时,设 $A_{x,y},B_{x,y}$ 分别表示只考虑 $xl=1,xr=n$ 的操作时 $a_{x,y}$ 的最终值,则同一行内 $A$ 不降 $B$ 不增,$\max(A_{x,y},B_{x,y})$ 在一段前缀内取 $A$,剩下的后缀内取 $B$。设该位置为 $p_y$,若能求出所有 $p_y$ 的值,可以拆分成两半分别进行上一段的扫描线,需要额外维护 $v_y$ 表示目前第 $y$ 行是否贡献,初始 $v$ 全为 $0$,过程中加入 $v$ 单点赋值为 $1$ 的操作,查询同样是历史和。

考虑 $p_y$ 怎么求,从下向上扫描线,则需要支持 $A$ 前缀或 $B$ 后缀 checkmax,两种均需支持撤销,查询最后一个 $A_x\ge B_x$ 的位置 $p_y$。由于区间改的撤销是困难的,考虑转为单点改 $A',B'$,则 $A$ 为 $A'$ 的后缀 max,$B$ 为 $B'$ 的前缀 max,使用线段树维护 $A',B'$,并在上面二分求 $p_y$ 即可,过程中需要记录目前后面的 $\max A'$ 和前面的 $\max B'$,时间复杂度 $O(n\log n)$。

剩下的问题是左右两轮扫描线,需要维护初始全 $0$ 的序列 $t,v$,支持 $t$ 区间 checkmax,$v$ 单点赋值为 $1$,查询区间 $tv$ 历史和。使用吉司机线段树,只在 $mn\lt v\le mn'$ 时打标记修改,同时使用一次函数维护历史和。注意这里懒标记也需要用一次函数,维护最小值变化过程中的贡献。时间复杂度不会分析,不知道是 $O(n\log n)$ 还是 $O(n\log^2 n)$,反正不超过后者且能过。

09.27

这回 T1 没挂。T2 挂了,原因是 DP 上界没有对 $m$ 取 min,理论上能卡到很低分但还有 $80$。

T3 是神秘调整贪心题,不会做。T4 是神秘 Hall 定理 + 数据结构,太困难。已严肃学习。

T2 在空无一物的时光深处

题意

有一个长为 $m$ 的画板,可任取笔刷的初始位置 $p$,需要依次涂 $n$ 种颜色,每次可选择终点 $q$ 为 $p-c_i+1$ 或 $p+c_i-1$,要求 $1\le q\le m$。之后将该区间内均涂成 $i$ 并将 $p$ 赋值为 $q$。求最终颜色不同的画板种类数。$n,m\le 150$。

题解

注意到顺着考虑时很容易记重,即一种画板形态对应多种最终位置。因此倒着考虑每次涂色,这时只能涂之前没涂过的位置,因此设 $f_{i,l,r,0/1}$ 表示考虑了后 $i$ 次涂色,当前有颜色的区间为 $[l,r]$,且笔刷最终位于左 / 右端点的方案数。注意到只有 $n$ 一种颜色时还是会重,因此要枚举第二种颜色作为 DP 初始值。

转移时需要枚举下一次真正涂出颜色的操作 $j$,并要求 $(i,j)$ 内的移动可以限制在 $r-l+1$ 长度内,且最终停在某个位置,之后拓展出去若干格即可。在某长度内移动的限制可以使用背包,设 $g_{i,j,lim,k}$ 表示考虑 $[i,j]$ 内的操作,不能超出 $[0,lim]$,最终能否到达 $k$。转移是 $O(1)$ 的,因此背包复杂度为 $O(n^2m^2)$。

然而此时 DP 需要枚举 $i,j,l,r$,还要枚举新染出去的长度 $d$,复杂度为 $O(n^2m^3)$,无法通过。然而注意到长度 $r-l$ 相等的 $f_{i,l,r}$ 均相同,因此这两维可以压成 $len$ 一维,状态数变成 $f_{i,len,0,1}$ 的 $O(nm)$,总复杂度降为 $O(n^2m^2)$,可以通过。

T3 烟花

题意

有 $n$ 种烟花,第 $i$ 种有 $c_i$ 个且点燃成功率为 $p_i$。要求从中选出 $k$ 个依次点燃,最小化某一个点燃失败且上一个点燃成功的期望次数。多组数据,$T\le 10,n\le 10^5,k\le 10^9,\sum c\ge k$。

题解

感觉非常不可做,需要挖掘其性质。令选择的烟花编号为 $a_i$,烟花总数为 $m=\sum c$。先考虑确定了选出的 $k$ 个烟花后如何排列,从而最小化 $\sum_{i=1}^{k-1} p_{a_i}(1-p_{a_{i+1}})=\sum_{i=1}^{k-1} p_{a_i}-p_{a_i}p_{a_{i+1}}$。首先最大化后一项,根据排序不等式或调整法可知升序或降序时最大,又由于 $p_{a_k}$ 不贡献,整个序列不降时取到最小值。

此时可以先把 $n$ 种烟花按 $p$ 升序排序,然而还是不好做,需要更深入的性质。若有 $x<y<z$ 三个值,贡献为 $x+y-xy-yz=y(1-x-z)+x$,于是有 $x+z\ge 1$ 时 $y$ 越大越好,$x+z\lt 1$ 时 $y$ 越小越好,因此 $y$ 一定会取到原序列中 $x$ 后一个或 $z$ 前一个。

这可以说明选择大概是比较集中的,下面尝试证明选的是一个前缀加一个后缀。首先有 $p_1(1-p_{a_2})\le p_{a_1}(1-p_{a_2})$ 且 $p_{a_{k-1}}(1-p_m)\le p_{a_{k-1}}(1-p_{a_k})$,因此 $1$ 和 $m$ 必选。之后设目前选的最长前缀为 $l$,最长后缀直到 $m-r+1$,并试图将离二者最近的元素调整进来。

具体地,若将 $a_{l+1}$ 调整为 $l+1$,则变化量为 $p_l(1-p_{l+1})+p_{l+1}(1-p_{a_{l+2}})-p_l(1-p_{a_{l+1}})-p_{a_{l+1}}(1-p_{a_{l+2}})$,整理可得 $(p_{a_{l+1}}-p_{l+1})(p_l+p_{a_{l+2}}-1)$,在 $p_l+p_{a_{l+2}}\le 1$ 时调整不劣;同理可得将 $a_{k-r}$ 调整为 $m-r$ 的变化量为 $(p_{m-r}-p_{a_{k-r}})(1-p_r-p_{a_{k-r-1}})$,在 $p_{a_{k-r-1}}+p_r\ge 1$ 时调整不劣。

这时若 $p_l+p_r\le 1$,由于 $p_{a_{l+2}}\le p_r$,可将 $a_{l+1}$ 调整为 $l+1$;否则 $p_l+p_r\ge 1$,由于 $p_{a_{k-r-1}}\ge p_l$,可将 $a_{k-r}$ 调整为 $m-r$,这就证明了最终一定能调整成一段前缀加一段后缀。

这也引出了做法:维护目前的 $l$ 和 $r$,若 $p_l+p_r\le 1$ 则加入 $l+1$,否则加入 $m-r$,重复该过程直到选出 $k$ 个。由于同种烟花的 $p$ 相等,可令 $l,r$ 一直为某种的端点,每次将 $l,r$ 不变的一段全放进来,可以做到关于 $n$ 线性。时间复杂度 $O(n\log n)$,在初始按 $p$ 进行排序。

原题

P4110

T4 归风

题意

定义序列 $b$ 权值为初始 $x=0$,每次操作可将 $x$ 增加 $1$,或让某个 $b_i$ 异或上 $x$,将 $b$ 全变为 $0$ 的最小操作次数即其权值。给出长为 $n$ 的序列 $a$,$q$ 次询问其 $[l,r]$ 区间内序列的权值。强制在线,$n,q\le 2\times 10^5,a_i\lt 2^{60}$。

题解

$x$ 的最终值是一个上界,可以任意使用不超过该值的数操作。先找出区间内 $1$ 的最高位 $2^p$,显然 $x\ge 2^p$,否则该位消不掉。之后所有不超过 $x$ 的数均可以一次消掉,其余数均需要两次消掉,答案为 $\min_{x\ge 2^p}(x+\sum_{i=l}^r[a_i\gt x]) +r-l+1$。将 $c$ 个 $a_i\gt2^p$ 的数和 $x$ 拿出来并减去 $2^p$,所求即 $\min(x+\sum_{i=1}^c[b_i\gt x])$,稍加转换即可得到 $c-\max(\sum_{i=1}^c[b_i\le x]-x)$,最终答案即 $2^p+r-l+1$ 加上这个值。

Hall 定理告诉我们,二分图最大匹配中左部失配点数为 $\max_S(\left|S\right|-\left|N(S)\right|)$。试图将上面的式子与其对应起来,则 $\left|N(S)\right|=x$,需要有 $x$ 个右部点,同时对应的左部点应该表示 $\sum_{i=1}^c[b_i\le x]$。考虑以每个 $b_i$ 为一个左部点,以每个整数值为一个右部点,左部 $b_i$ 向所有满足 $x\le b_i$ 的右部点 $x$ 连边,显然这是一个前缀。因此 $N(S)$ 也总是一个前缀,当其为 $[1,x]$ 时会选择所有 $b_i\le x$ 的 $b_i$,这是合法的最大 $S$,容易发现其他情况不会得到比原式更大的结果,因此这样构造是对的。

这样在该图上求出最大匹配数,即为所求的 $c-\max(\sum_{i=1}^c[b_i\le x]-x)$。由于左部点向右边前缀连边,以任意顺序枚举左部点并找最大右部点与其匹配是对的,不妨钦定顺序从右到左将 $[l,r]$ 内的点尽量匹配。对整个序列从左到右扫描,并实时维护 $[1,r]$ 从后往前依次匹配的结果。

由于后面的优先级更高,新加入 $r$ 时会强制匹配 $r$,这可能导致整个匹配不合法。仍然使用 Hall 定理,不合法也就是存在 $x$ 使得 $\sum_{i\in S}[b_i\le x]-x\gt0$。使用线段树维护每个 $x$ 的这个值,加入 $r$ 时对 $b_r$ 的后缀加 $1$,此时若存在 $x=1\gt0$,就找到最小的 $x$,再从 $x$ 前面找到编号最小的 $t$,将其从匹配中删去,从而保证 Hall 定理的条件仍然成立。容易发现某元素删去后一定不会再加回来,因此这是对的。

综上,线段树需要维护区间最大值及第一个最大值的位置,还要支持在每个点上维护一个集合,查询前缀集合内最小元素,这都是不难实现的。由于每个询问最高位 $2^p$ 唯一,且此时只关心 $(2^p,2^{p+1})$ 内的数,对所有这样的集合分别预处理该过程即可。由于区间无交,总复杂度是 $O(n\log n)$ 的。

此时得到了每个点在 $r\in[i,lim_i]$ 时在匹配中,同时还有 $l\le i$ 的限制,大概是平面内矩形加,每个询问相当于单点查询。对每个 $2^p$ 分别开一棵主席树,从而可以支持在线回答询问。同样由于区间无交,总复杂度也是 $O((n+q)\log n)$ 的。另外为了快速查询区间最高位,可能需要用 ST 表维护区间最大值,做到 $O(n\log n+q)$。

然后仔细看了一眼我代码,猛然发现理论复杂度瓶颈在查询单个值最高位的 $O(n\log V)$,抽象。使用 __builtin_clzll 做到 $O(1)$ 之后总时间复杂度为 $O((n+q)\log n)$。

原题

P12559

09.29

单打 ACM 了说是,自己过了四个题。C 太唐了,G 我唐了,其他还行,发挥正常。

A 酒吧

题意

给出 $n$ 个位置,每个位置有值 $a_i$,现需选择一部分位置标记,之后每个位置两边最近的标记位置值均会贡献到总和一次,求最大总贡献。多组数据,$n\le 5\times 10^5,\sum n\le 3\times 10^6$。

题解

首先 $1$ 和 $m$ 必选,否则选上答案一定不降,之后发现答案是 $\sum_{i=1}^{k-1} (p_{i+1}-p_i)(a_{p_{i+1}}+a_{p_i})$。考虑寻找其意义,将 $(i,a_i)$ 标在坐标系上,发现该贡献即两点连线与 $x$ 轴围成直角梯形面积的两倍。因此要最大化所有梯形面积的和,显然选上凸包上所有点最优,维护出凸包后计算答案即可。时间复杂度 $O(n)$。

原题

QOJ5500

E 数论方程

题意

给定 $n,p$,求一组满足 $1\le x\lt y\lt z\lt p$ 且 $(x+y+z)(x^n+y^n+z^n)(x^{2n}+y^{2n}+z^{2n})\equiv x^{3n}+y^{3n}+z^{3n} \pmod p$ 的整数 $(x,y,z)$。多组数据,$T\le 10^5,n\le 10^9,5\le p\le 10^9$ 且 $p$ 为质数。

题解

三个未知数却只有一个方程,只需要求出任意解即可。考虑只找出一个主元,将其表示出来再由此构造解。令 $x=at,y=bt,z=ct$,代入并化简可得 $t=\frac{a^{3n}+b^{3n}+c^{3n}}{(a+b+c)(a^n+b^n+c^n)(a^{2n}+b^{2n}+c^{2n})}$。

这时只需找到 $(a,b,c)$ 使得 $a,b,c$ 两两不相等,且分数中四项均非零即可。可以证明若在值域内随机选择 $a,b,c$,单个式子为零的概率不超过 $\frac 14$,于是随常数次就可以找到答案。时间复杂度 $O(T\log n)$,来自计算过程中的快速幂。

原题

ARC158D

F 野蛮 5

题意

给出一个森林,两人轮流操作,每次删掉一条边或一个点及其邻边,无法操作者负,问先手是否必胜。$n\le 2\times 10^5$。

题解

手玩一下感觉很有性质,这里直接给出结论:当且仅当 $n,m$ 均为偶数时后手必胜。证明考虑终止状态显然满足条件,接下来证明其他情况均可一步操作到 $n,m$ 均为偶数,而这种情况无法在操作一次后保持。分讨:

  • $n,m$ 均为奇数:删掉一个叶子节点,$n,m$ 均减小 $1$。
  • $n$ 为奇数,$m$ 为偶数:删掉一个度数为偶数的点,$n$ 减小 $1$。由于度数总和为偶数,点数为奇数,这样的点一定存在。
  • $n$ 为偶数,$m$ 为奇数:删掉一条边,$m$ 减小 $1$。
  • $n,m$ 均为偶数:删点和删边后 $n,m$ 分别为奇数,无法保持。

因此,操作时若 $n,m$ 不均为偶数,不断将其变成均为偶数即可取胜,结论得证。只读入 $n,m$ 即可输出答案,时间复杂度 $O(1)$。

第一次见不用读完输入的题。话说 LCA 还有 SG 函数做法,是本质相同的,只是推导过程略有不同,此处略去。

原题

QOJ2323

H 醉晓生成树

题意

有一个 $n$ 个点的完全无向图,每条边有 $p_0$ 的概率不存在,有 $p_i$ 的概率边权为 $i$。对所有 $t\in[n-1,k(n-1)]$,求图的最小生成树边权和为 $t$ 的概率。多组数据,$T\le 200,n\le 40,k\le 4$,且 $n\gt 20$ 的数据不超过 $2$ 组。

题解

考虑类似最小生成树的求解过程,按边权从小到大依次加边。暂且抛开计算边权和不谈,求 $f_{t,i}$ 表示 $i$ 个点被不超过 $t$ 的边连通的概率。考虑从节点 $1$ 开始,考虑连通块拓展的过程,初始为 $1$ 点由不超过 $t-1$ 的边形成的连通块,再通过 $t$ 边接上一些由不超过 $t$ 的边形成的连通块。

考虑再维护一个转移系数 $g_{i,j}$,表示目前 $i$ 个点的连通块新加入 $j$ 个点的概率。按点数从小到大考虑,考虑到大小 $s$ 先用 $g$ 中小于 $s$ 的部分求出 $f_{t,s}$,再用 $f_{t,s}$ 更新 $g$。这正确是因为初始连通块至少包含 $1$ 点,因此接上的总大小不超过 $s$。

$f$ 的转移显然为 $f_{t,s}=\sum_{i=1}^s f_{t-1,i}\times g_{i,s-i}\times {s-1\choose i-1}$,即枚举初始连通块大小为 $i$。$g$ 转移时需要所有新连通块间边权大于 $t$,新连通块与初始连通块间边权不小于 $t$,且存在至少一条 $t$。同时由于大小相同的连通块无法区分,加入 $k$ 个 $s$ 时还要额外除以 $k!$,防止算重。具体转移式此处略去,容易发现该 DP 的总复杂度为 $O(kn^3\log n)$,瓶颈在求 $g$ 时每个 $(i,j)$ 枚举所有 $(s,k)$,而 $(s,k)$ 的数量为调和级数的 $O(n\log n)$。

考虑将最小生成树的边权和考虑进来,比较暴力的方式是在 $f,g$ 中加维,加入 $S$ 表示总边权和,转移只需要在 $g$ 内加入新连通块时额外加 $t$ 即可,其余转移会加上一个背包状物,答案为 $f_{k,n}$。由于 $S$ 为 $O(nk)$ 级别,这样总复杂度要乘上 $n^2k^2$,为 $O(k^3n^5\log n)$,比较爆炸。

对于这种转移复杂度较高的背包,可以考虑使用插值优化。具体地,不再在状态中维护 $S$,转而直接维护一个多项式 $F(x)=\sum_{S=0}^{nk} p_S\cdot x^s$,其中 $p_S$ 表示边权和为 $S$ 的概率。然而直接用多项式乘法转移还是慢,即使上科技也得多带 log。由于多项式次数为 $O(nk)$,直接取 $x\in[0,nk]$ 分别代入求出最终 $F_{k,n}(x)$ 的值,这样转移时只有数字的转移,单轮复杂度仍为 $O(kn^3\log n)$。最后对 $F_{k,n}(x)$ 插值求出系数即为答案,这里复杂度为 $O(n^2k^2)$,于是总复杂度优化到了 $O(k^2n^4\log n)$,可以通过。

J 开拓

题意

交互。有一棵 $n$ 个点的树,每次可询问一个点集,得到其虚树叶子节点的编号和及其中之一的编号,还原整棵树。$n\le 1000$,询问次数不超过 $10^4$。

题解

$10^4$ 大概是 $O(n\log n)$ 级别,这启发我们使用二分状物。首先第一次询问整棵树 $S$,可得到 $u$ 节点为叶子,以及目前叶子节点编号和 $x$。将 $u$ 放入待连边集合 $T$ 并从 $S$ 中删除得到 $S'$,同时更新 $x$ 为 $x-u$。

之后查询 $S'$ 得到新的叶子节点编号和 $y$。若 $x\ne y$ 则说明删去 $u$ 后产生了新的叶子 $v=y-x$,这时可从 $T$ 中找到若干 $v$ 的儿子,方式是二分出最短前缀使得 $S'$ 加上这个前缀后 $v$ 不为叶子,这可以通过一次询问判断。不断寻找直到不存在 $v$ 的儿子即可。由于每个点只会从 $T$ 中被找出一次,总次数是 $O(n\log n)$ 的,可能会由于中止寻找的那轮二分带点常数,然而还是能过的。

10.02

时间分配有些问题,也不好说,反正由于水平等各种原因没时间做 T4 了。

T4 魔法相机

题意

给出若干个区间 $[l,r]$,可选若干非负整数点 $p$,要求任意两点之间距离不小于 $s$,求最多能覆盖的区间个数。$n\le 2\times 10^5,s,r_i\le 10^9$。

题解

考虑暴力 DP,设 $f_{x,i}$ 表示考虑了所有 $r\le x$ 的区间,此时最后一个点为 $i$ 最多能覆盖的区间个数。当从 $f_{x-1}$ 转移到 $f_x$ 时,有 $f_{x,x}=\max_{j=0}^{x-s}f_{x-1,j}$,之后枚举所有 $r=x$ 的区间,并对 $[l,x]$ 内的 $f_{x,i}$ 加一。

$n$ 次后缀容易使用线段树维护,然而前缀查最大值 $V$ 次太多了,无法接受。考虑寻找关键点,并只在这些点上转移。显然区间左端点 $l$ 均可能成为最值,然而这还不够,$l+m$ 处可能继承 $l$ 的信息,因此 $l+m$ 应该作为辅助点进行转移。然而辅助点也可能产生新的辅助点,数量还可能很多,还要优化。

考虑一个辅助点 $x$,若上个转移点为 $y$ 且 $f_x\le f_y$,则 $x$ 被 $y$ 支配,即之后 $f_y$ 一直不小于 $f_x$。证明考虑存在 $y\lt l\le x$ 的区间加时,$f_x$ 才可能变得比 $f_y$ 大,然而此时上个关键点变为 $l$,因此这种情况不存在。于是用堆维护所有转移点和区间,根据上述条件 $f_x\gt f_y$ 加入新点即可。

该做法正确性没有问题,然而关于时间复杂度,可以证明转移点的个数是 $O(n)$ 的,但我不太会证,感性理解是每 $O(1)$ 个点 $f$ 值就会增加,同时答案不超过 $n$。题解区有一些不太完整的证明,没看明白,不管了,总之用动态开点线段树可以做到 $O(n\log n)$。

原题

CF542B

T5 小小的希望

题意

给定一棵树,父亲数组 $f$ 满足 $f_{i-1}\le f_i\lt i$,$q$ 次询问区间 $[l,r]$ 内 LCA 仍在区间内的点对点权乘积之和,即 $\sum_{x=l}^{r}\sum_{y=l}^r [l\le L(x,y)\le r] a_xa_y$,强制在线。$n,q\le 2.5\times 10^5$。

题解

由于 $f_i\lt i$,所以当 LCA 在区间内时,路径上的所有点均在区间内。因此区间内的点构成若干个连通块,每个连通块内两两选点均合法,贡献为 $(\sum a_i)^2$,所有连通块贡献和即为答案。另外还有 $f_{i-1}\le f_i$ 的限制,这说明树的节点编号形成 BFS 序。

考虑设 $t_i$ 表示 $i$ 点当前块的 LCA,$s_i$ 表示以 $i$ 为 LCA 的块 $a$ 的和。类似莫队移动端点,右端点改变时容易找到其对应 $t_i$ 并更新,复杂度 $O(1)$。然而左端点改变时需要合并新点的所有儿子,复杂度为 $O(d_i)$,其中 $d_i$ 为 $i$ 点度数。因此分块时除了要保证每块点数不超过 $B$,还需要保证 $\sum_{i=L+1}^r d_i\le B$。于是从后往前分块,每当某个限制爆掉就分成一个块。由于点数和 $\sum d$ 都是 $O(n)$ 的,总块数仍是 $O(\frac nB)$,可能要带上两倍常数。、

这时使用回滚莫队,每次先拓展右端点更新,再拓展左端点合并,实时维护当前 $\sum(\sum a_i)^2$ 即可。然而本题强制在线,考虑预处理全部 $O((\frac nB)^2)$ 对块间信息,每次取出信息再移动端点。需要知道的信息有右边块每个点的 $t_i$ 及 $s_{t_i}$,左边块每个点所有儿子的 $s_v$,共需要 $O(B)$ 的空间,可能有三四倍常数。取 $B=\sqrt n$ 可得理论最优时空复杂度 $O(n\sqrt n)$。然而空间常数过大炸掉了,卡不过去,于是开到 $B=1.55\sqrt n$ 后时空都极限过了,不管了。

10.03

T3 应该想到括号树的,最大败笔。然而这两场都没挂分,爽了。

T3 数括号

题意

有一个长为 $2n$ 的括号串 $s$,每次新增一条限制 $l,r$,表示最终括号序列中 $s_l,s_r$ 匹配,求每次增加限制后的合法括号序列数,保证有解。$n\le 5\times 10^5$。

题解

考虑所有匹配的括号对,若其内部无匹配括号,则内部一定是合法括号序列,用卡特兰数即可计算。之后可删掉这些位置,又会产生新的极小括号对。这样一直做下去就能求出答案。

考虑该过程实际上在干啥,发现将所有已知配对建成括号树,之后每个点内所有不在其子树内的位置形成一个合法括号序列,可以用卡特兰数直接计算。然而正着向括号数中加匹配比较困难,考虑用最终括号序列建树,之后倒着删树上的点,每次需要找到其当前父亲并修改其位置数。用树上并查集即可实现该操作,时间复杂度 $O(n\lpha(n))$。

T4 异或数组

题意

给定数组 $a$,保证 $0\le a_i\lt 2^m$。每次询问给出 $l,r$,求 $\max_{x=0}^{2^m-1}\min_{i=l}^r(x\oplus a_i)$。$n\le 10^5,q\le 5\times 10^5,m\le 50$。

题解

考虑单次询问怎么做,可以建出 Trie 树并在上面 DP,若当前点只有一个子树,则该位可为 $1$,再递归进该子树求解;否则该位必为 $0$,可选择一个子树作为后面位的贡献。实现上类似树形 DP,时间复杂度 $O(nmq)$。然而这告诉我们最终答案一定在 Trie 树上(虽然事实上所选的 $x$ 应该恰好是该节点的补集),启发我们改为对每个 $a_i$ 考虑。

具体地,对每个 $a_i$ 统计答案,则需关注 Trie 中其到根的路径上所有点,若没有兄弟节点则该位可产生贡献。于是找出 $l_{i,k},r_{i,k}$ 表示 $i$ 两边最近的 Trie 树上第 $k$ 位邻居,当且仅当 $L\le l_{i,k}\le i\le r_{i,k}\le R$ 时选择 $a_i$ 会产生 $2^k$ 贡献。注意到若 $i$ 不在区间内则贡献一定不优,于是与 $i$ 有关的限制可以删去,只剩 $L\le l_{i,k}\le r_{i,k}\le R$。

$l,r$ 各有 $m$ 个限制,两边共有 $O(m^2)$ 种可能的限制情况,也就是 $O(m^2)$ 个 2-Side 矩形 checkmax,单点查询。这可以使用扫描线维护前缀修改并单点查,用树状数组可以做到 $O(nm^2\log n+q\log n)$。然而发现前一项很大而后一项不大,使用 $O(1)$ 修改 $O(\sqrt n)$ 查询的分块可以平衡到 $O(nm^2+q\sqrt n)$,可以通过。

10.06

打得最好的一集。没挂而且暴力怎么过 $85$?反正 rk1,爽了。

T4 神谕

题意

给出一棵广义线段树,对其进行区间加操作,询问某个点目前的标记值。$n,q\le 2\times 10^5$。

题解

考虑用更简洁的方式刻画标记的加入和下传,关注 $l-1$ 和 $r+1$ 两条链,求出其 LCA,则 $l-1$ 到 LCA 路径上的点不在路径上的右儿子会被打标记,$r+1$ 同理。同时这些点到根的路径要下传标记,这可以找到两条链上有对应儿子的最深点,改为这两个点到根的路径清空标记,这会导致对其邻域打标记。

暂且放下实现不表,先分析一下标记下传的总次数。若 $u$ 点存在一个标记 $x$,则不管是直接加还是下传下来的,一定是某次在其兄弟子树内的操作导致的;同理若要下传 $u$ 点的标记,一定是某次在其子树内的操作导致的。因此下传的总标记数不超过 $2 \sum_{u}\min(s_{lc_u},s_{rc_u})$,其中 $s_u$ 表示 $u$ 子树内的操作次数。根据启发式合并的复杂度分析,这是 $O(q\log n)$ 级别的。

再来考虑实现,先对其树剖,再开两棵线段树分别维护链的左右儿子加。操作时直接在对应线段树上对某点到根的路径加,则符合儿子限制的点标记为 $w_{fa_u}-w_u$,这可以保证真正被打上标记的点在链外。

某个点到根的路径清空标记时,依次处理从根到该点的链。注意不能每次将标记下传给儿子,这会使复杂度退化到暴力,还比暴力多个 log。需要按带标记的点将链分成若干段,每段都对邻域加上比其深度小的标记和。所以线段树需要维护标记点位置,我的实现可能还需要维护前两个标记点,还要注意跨过轻边的处理。单次复杂度为 $O(\log n(\log n+c))$,其中 $c$ 为标记点个数。于是总复杂度为 $O(q\log ^2n)$,可以通过。细节一车,5k 代码写了一天

10.09

最大败笔是会 T4 但 MLE 了,之后还是要注意时空限制,避免失误。

T3 日历

题意

有 $n$ 个 $m$ 位十进制数满足 $a_i=a_{i-1}+1\bmod 10^m$,存在若干已知位,构造一个合法的 $a_1$。$nm\le 10%^5$。

题解

注意到从后往前第 $i$ 位每 $10^{i-1}$ 行会加一,于是超过 $\log_{10}n$ 的位最多只会加一次。考虑对后 $5$ 位暴力枚举所有合法的 $a_1$,则这些位上每个限制形如 $a_1\bmod 10^j$ 在一个区间内,差分即可判断合法性。

枚举合法 $x$ 后可算出在第 $h$ 行向前进位。这时再枚举进位到第 $w$ 列,要求 $(h,w)$ 右上角全为 $9$,右下角全为 $0$,第 $w$ 列在 $h$ 上方为 $x$,下方为 $x+1\bmod 10$,且所有行的前 $(w-1)$ 列均相同。一个角全为某数可以用前缀和预处理,其余可预处理每列的限制情况。时间复杂度 $O(P+nm)$,其中 $P=10^5$。

T4 奶龙哞叫

原题:P11459,题解见【学习记录】凸优化

注意这种分治结构不用 $O(n\log n)$ 的空间,可以每层只分配两个 vector,在 $u$ 点处分别将下层的空间分给两个儿子使用,合并到 $u$ 后就用不到了。由于第 $i$ 层单个节点所用空间为 $O(\frac n {2^{i-1}})$,总空间复杂度只有 $O(n)$,在本题中为 $O(nL)$。

10.11

整体还行,但 T3 犯唐写麻烦了,不然可能还能多冲点 T4 的。

T4 冒泡排序二合一

题意

给定排列 $a$,$q$ 次询问对 $[l,r]$ 区间进行 $k$ 轮冒泡排序后,$x$ 值的位置或 $a_x$ 的值。$n,q\le 6\times 10^5$。

题解

对于求 $x$ 值的位置,考虑转为两个 $01$ 序列,分别为 $b_i=[a_i\ge x]$ 和 $c_i=[a_i\gt x]$,对 $b,c$ 分别做 $k$ 轮冒泡排序后,两者不同的位置即最终 $x$ 的位置。此时若 $x$ 为 $b$ 中前 $k$ 个 $1$,则 $b$ 的第 $(k+1)$ 个 $1$ 不动,而 $c$ 的该位置作为第 $k$ 个 $1$ 移走了,于是有且仅有 $c$ 序列该位置前的 $0$ 最终在 $x$ 之前。

若 $x$ 不为 $b$ 中前 $k$ 个 $1$,则两序列该位置均不动,因此 $x$ 只会向左移动 $k$ 位。综上需要求区间内第 $k$ 个 $1$ 的位置,离线后按值从大到小扫描线,用树状数组维护 $01$ 序列并在上面二分即可,复杂度 $O((n+q)\log n)$。

对于求 $a_x$ 的值,显然若其在后 $k$ 个位置内,则一定是对应排名的数,即区间第 $r-k+1$ 大值。否则有 $x+k\le r$,考虑用 $[l,x]$ 的区间和减去 $[l,x-1]$ 的区间和。不难发现 $[l,x]$ 的区间和为 $[l,x+k]$ 区间内除前 $k$ 大外的和,证明可按 $[l,x+k]$ 区间第 $k$ 大转为 $01$ 序列,最终 $[l,x]$ 内一定没有 $1$,因此一定是所有 $0$ 的和。

实现上可以使用主席树查询区间第 $k$ 大以及对应的和,可以在线回答询问。时间复杂度也是 $O((n+q)\log n)$ 的。

10.13

T4 太难了,拼尽全力无法战胜多项式做法/ll。结果两个 Div 都没人过,确实太难了。前边打得还行,没有挂分。

T4 圆周距离问题

题意

$n$ 个点的环,相邻两点距离为 $1$。一种选点方式的代价定义为两两之间最短距离的最大值,求所有选 $k$ 个点的方式代价之和。$2\le k\le n\le 10^6$。

题解

枚举代价 $x$,设 $f_x$ 表示代价不低于 $x$ 的方案数,则答案为 $\sum_{x=1}^{\lfloor \frac n2\rfloor } f_x$,每种方案的贡献拆成了多段。然而这个难求,考虑求出 $g_x$ 表示代价不超过 $x$ 的方案数,则有 $f_x={n\choose k}-g_{x-1}$,于是求 $g$ 即可。

环上比较难考虑,需要断环为链。考虑任取一个被选点放在 $0$ 处,之后将环放到 $[0,n-1]$ 上,求此时合法方案数。这样求出方案数后放回环中有 $n$ 种位置,然而每种方案还会被 $k$ 个点各计算一次,于是最后还要乘上 $\frac nk$。

当计算距离不超过 $x$ 的答案时,显然只能在 $[1,x],[n-x,n-1]$ 内选点,且两部分内部不会非法,只需考虑两部分之间的限制。若选了 $p\in[n-x,n-1]$ 点,则 $[p+x+1-n,p-x-1]$ 内无法选点。注意到左端点 $x+(p+1-n)$ 一定在 $[1,x]$ 内,且长度均为 $d=n-2x-2$。于是将 $[n-x,n-1]$ 整体向后平移 $x+1$ 格到与 $[1,x]$ 重合,之后考虑长为 $x$ 的选择。

将移过来的点看成黑点,本来在 $[1,x]$ 内的点看成白点。现要从 $x$ 个点中选 $(k-1)$ 个并染成黑白两色,要求黑点之后 $d$ 个不能是白点。于是枚举黑色变为白色的次数 $i$,一定有 $id\le x$。在开头放一个白点,结尾放一个黑点,强制分成 $(2i+2)$ 段,于是分段方案可用隔板法计算为 $k\choose 2i+1$。之后先从 $x$ 个点中删掉 $id$ 个分隔符,从剩下的位置里选出 $k-1$ 个位置,再将分隔符插回分界位置即可,方案数 $x-id\choose k-1$。

于是有 $g_x=\sum_{i=0}^{\min(\lfloor \frac xd\rfloor,\lfloor \frac {k-1}2\rfloor)} {x-id\choose k-1}{k\choose 2i+1}$,预处理阶乘即可单次 $O(1)$ 计算,枚举量是调和级数的 $O(n\log n)$,可以通过。

原题

AGC068A

10.16

T4 太难了,无法战胜,史哥太强了。整体还行,T5 看起来可补,之后有时间再说吧。

T4 放球程序

题意

有 $n$ 个球和 $n$ 个盒,编号均为 $1$ 到 $n$,初始可任意将球放到盒内。要求对 $i$ 从 $1$ 到 $n$ 依次操作,每次拿出 $i$ 盒内的球并任意排列成 $p_k$,之后同时将所有 $p_j$ 球放到 $p_{j+1\bmod k}$ 盒中。给出最终每个球所在盒的编号 $a_i$,判断是否可能出现该最终局面。多组数据,$\sum n\le 2.5\times 10^5$。

题解

发现顺序操作时自由度太高了,初值和过程中的排列顺序均难以确定,于是考虑倒着做,这样初始状态确定了。将状态用图表示,即球编号 $i$ 向所在盒编号 $a_i$ 连边,形成基环树森林。则对 $i$ 操作时所有指向 $i$ 的点均断开,再以任意顺序连成一个环;倒过来考虑时即找到一个环,将其断开并全部指向 $i$。

注意到上述两操作并不等价,原因是前者要求取所有指向 $i$ 的点,而后者没有限制这一点。仔细思考后发现只有两种情况合法,分别是 $i$ 点入度为 $0$ 或 $i$ 点在环上且入度为 $1$。前者可任意选环操作,后者必须选 $i$ 点所在的环,这对应操作前 $a_i=i$ 形成自环,会将其操作后环上前驱代表的球留在 $i$ 盒内。

于是出现了新的自由度:$i$ 点不在环上时可任意选环。猜想选 $i$ 所在连通块的环最优,手推发现选其他环时,除 $i$ 点外所有点的可操作性均不变;选所在连通块的环时,$i$ 点到环路径上入度只比限制多 $1$ 的点由不可操作变为可操作,其余点仍不变,于是这可能使局面变得更可操作,一定是最优的。

于是有了一个确定过程:从初始 $(i,a_i)$ 形成的图开始,倒序操作所有 $i$。每次先检查入度是否合法,不合法则无解;否则找到该连通块内的环,将其断开并全部指向 $i$,过程中修改入度。若能进行完 $n$ 次操作则有解。直接模拟该过程,暴力跳后继找环,复杂度可证明不超过 $O(n\sqrt n)$,事实上跑得特别快,证明如下(By Kevin090228):

每次操作遍历操作点到环路径上和环上的所有点。由于路径上的点在操作后会变到环上,只分析每次操作环长 $L$ 的总和即可,即复杂度为 $O(\sum L)$。设局面 $S$ 的势能 $V(S)=\sum r_i^2$,即所有点入度的平方和。操作会使环上点的入度减 $1$,势能减小 $\sum_{t\in C} r_t^2-(r_t-1)^2=\sum_{t\in C} 2r_t-1$,由于全局入度和为 $n$,这是不超过 $2n$ 的;同时操作点 $x$ 入度增加环长 $L$,势能增加 $(r_x+L)^2-r_x^2=2Lr_x+L^2$,这是不低于 $L^2$ 的。

由于势能 $V(S)$ 上界为 $n^2$ 且 $n$ 次操作总减小量不超过 $2n^2$,总增加量一定不超过 $3n^2$。忽略 $2Lr_x$ 这一项,有 $\sum L^2\le 3n^2$,根据柯西不等式可得 $\sum L$ 至多是 $n\sqrt n$ 级别的,于是复杂度 $O(\sum L)$ 不超过 $O(n\sqrt n)$。

还有另一种做法,考虑进一步刻画合法局面,注意到操作点 $i$ 时要求 $i$ 没有环外入度,因此对于 $i$ 点不在环上的前子树 $u$,若其所有点编号均小于 $i$,则 $i$ 点操作前该子树不变,$i$ 点会由于 $(u,i)$ 存在而无法操作,必然无解。于是对于每个点 $i$,其每个子树 $u$ 最大值 $w_u$ 均需满足 $w_u\gt i$,才有可能有解,这是一个必要条件。

至于充分性,感性理解若满足条件,则每个子树内都有点操作过,从而 $(u,i)$ 这条边曾被纳入环中,不再构成限制,因此 $i$ 点此时可以操作,不太会严格证明。总之这个条件是充要的,据此可判断合法性,DFS 即可找出环并求出所有 $w_u$,时间复杂度 $O(n)$,然而没跑过上种做法

原题

AGC068C

10.18

T4 太难了,无法战胜。整体还行,T5 没看而且似乎比较思维,于是弃了。

T4 优美子数组

题意

定义数组 $b$ 划分的优美值为每段和的绝对值最小值。给定数组 $a$,要求支持单点修改,查询区间最大优美值。$n,q\le 10^6$。

题解

考虑优美值如何计算,分段方案的每一段均有正或负的权值,显然相邻段同号一定不优,可以将其合并,于是首先调整为正负交替。再注意到每相邻四段 $a,b,c,d$ 一定能将 $b,c$ 中绝对值较小的一个与两边合并,这也是不劣的。于是最终不超过三段。还能注意到此时若中间段绝对值不严格最大,则合成一整段更优。

综上,只能分一段(区间和),分两段(从前缀和最大最小值分开)或分三段且中间段绝对值严格最大。前两种均容易使用线段树维护,问题在于第三种的求解。考虑枚举分界线,钦定两个分界点在线两侧,则一定会选择从外侧起前 / 后缀和最值位置断开。

更具体地,对数组 $b_m$,其分三段正负正的最大优美值为 $\max_{i=0}^n(\min(p_i,s_{i+1}))$,其中 $p,s$ 分别表示前 / 后缀内前 / 后缀和的最大值,负正负同理。这显然能取到最优解,同时由于中间一段绝对值不最大时不优,这也不会比实际最优解大,于是这样求是对的。

根据定义,$p,s$ 分别不降和不增,于是最大值一定在两者图像交点处取到。具体地,若在序列上可对 $i$ 二分,找到第一个大小关系变化的位置。在线段树上可取出所有节点,先对这些位置二分出交点所在的段,再在线段树上进入该段二分,应该也能递归写,没试。总复杂度 $O(n+q\log n)$。

原题

P12554

10.20

怎么四个全会,怎么挂了两个,被 corner case 爆了。离 AK 最近的一次,不过这也是为什么我们要认真处理细节,之后需要注意。

浅谈有偏序限制的排列字典序问题

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

做 AGC001F 的时候想的,结果越想越乱,总结一下。

  • 逆排列:对 $p$ 来说满足 $q_{p_i}=i$ 且 $p_{q_i}=i$ 的排列 $q$。事实上两个条件等价,都是值与下标互换。
  • 引理:最小化 $p$ 的字典序,相当于最大化其逆排列 $q$ 的逆序字典序。

考虑 $p$ 字典序最小在 $q$ 上是什么,发现要让 $1$ 尽可能靠前,再让 $2$ 尽可能靠前,以此类推。因此倒着进行这个过程,直到只能填 $1$ 时才填 $1$,否则在只能填 $2$ 时填 $2$,这对应其字典序最大。

有以下三个问题:

  • 要求排列中 $i$ 在 $j$ 之前出现,求字典序最小的排列 $p$。

相当于字典序最小的拓扑序,因此直接由 $i$ 向 $j$ 连边,每次取入度为零的最小值放在 $p$ 开头即可。

  • 要求 $p_i<p_j$,求字典序最小的排列 $p$。

比较自然的想法是 $i$ 向 $j$ 连边,之后每次取最小编号并赋值。然而这是错的,容易用 $n=3,(3,1)$ 直接卡掉。

这是因为该过程并没有尽可能最小化 $p_1$,而是最小化了 $p$ 的逆排列 $q$ 的字典序。然而根据引理,实际上要做的是最大化 $q$ 的逆序字典序。

该限制转化到 $q$ 上为 $i$ 在 $j$ 之前出现,求逆序字典序最大的排列 $q$,根据上一题这需要由 $j$ 向 $i$ 连边,并倒着确定每个 $q$ 的取值,之后再转化回原排列 $p$。

然后发现这次的拓扑排序部分与上题相比取了个逆,这与 $q$ 转化回 $p$ 的取逆抵消了。因此本题可以直接由 $j$ 向 $i$ 连边,每次取最大编号并赋值, 这与上一段中的做法等价。

  • 要求排列中 $i$ 在 $j$ 之前出现,之后要求先让 $1$ 尽可能靠前,在此前提下让 $2$ 尽可能靠前,以此类推。

再次考虑逆排列 $q$,发现这其实就是 $q_i\lt q_j$,求字典序最小的排列 $q$,只需要对上题的结果取逆排列即可得到答案,这可以直接在拓扑排序部分修改。本题有原题 HDU4857

【听课记录】25.10-LCA-Week2

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

这周内容太爆炸了,所以基本没补,之后有时间再说吧。

10.01 降维

  • 最值降维

TEST_73(未公开)

题意

给定一棵树,$q$ 次询问只保留编号在 $[l,r]$ 内的点和边后点连通块个数。$n,q\le 10^6$。

题解

直接点边容斥,边被保留需要两个端点均被保留,在一个矩形内有贡献,直接扫描线即可,复杂度 $\mathcal O((n+q)\log n)$。没题写不了。

  • 常数种斜率降维

未公开题目

题意

给定 $n$ 个区间 $[l,r]$,$q$ 次询问给出 $L,R,k$,求满足 $L\le l\le r\le R,r-l+1\ge k$ 的区间个数。$n,q\le 2\times 10^6$。

题解

按长度扫描线,这样已经解决了 $r-l+1\ge k$ 的限制。之后可容斥转化为求 $\sum[r_i\le R]-\sum[l_i\lt L]+\sum[l_i\lt L][r_i\gt R]$,画到平面上也有相同结论。由于询问的 $R-L+1\ge k$ 才可能有答案,最后一个式子可以忽略长度限制单独求。于是要做三遍单点加求前缀和的扫描线,树状数组即可,复杂度 $\mathcal O((n+q)\log n)$。没题写不了。

这里 lxl 说若三维中有两维对称,一般枚举 / 扫描不对称的那一维。比如本题中左右端点对称,于是扫描剩下的长度维可能比较好做。

P11621 [Ynoi Easy Round 2025] TEST_139

先差分,将查询矩形差分成 $X\ge a,Y\ge b$ 的形式。之后讨论修改 $(x,y,d)$ 对询问 $(a,b)$ 的贡献形式,发现所有的贡献条件都是二维偏序,只是贡献有的是二次函数,多维护几个值进行带修二维数点即可,可以 CDQ 分治解决,复杂度 $O((n+q)\log ^2n)$。之后应该会写。

这里 lxl 说能差分就差分,大部分情况下连常数都不会变大。

请输入文本

题意

给定 $n$ 个区间 $[l,r]$,每个区间有权值 $w$,保证两两不包含。$q$ 次询问给出 $L,R,k$,求满足 $L\le l\le r\le R,r-l+1\ge k$ 的区间权值和。$n,q\le 2\times 10^6$。

题解

$l,r$ 两维分别递增,画在二维上连起来是折线,因此 $l,r$ 的二维限制一定对应折线上的一段,限制变成了一维的。直接扫描长度一维即可,复杂度 $\mathcal O((n+q)\log n)$。没题写不了。

P9061 [Ynoi2002] Optimal Ordered Problem Solver(弱化)

题意

给出二维平面上 $n$ 个点 $(x,y)$,支持删除 $x\le X,y\le Y$ 的所有点,询问矩形和。$n,m\le 2\times 10^6$。

题解

由于删除的是一个左下角矩形,删除点形成一段折线。之后对询问差分成左下角矩形。之后容斥,如果已经在折线下方则答案为 $0$,否则分别求询问上方、右方、右上方的和,容斥一下可以得到答案。动态一维偏序和静态二维偏序,均可 $O(n\log n)$ 维护。弱化写不了。

P8337 [Ynoi2004] rsxc(弱化)

题意

给定 $n$ 个区间 $[l,r]$,保证两两不包含。询问给出区间 $[L,R]$,求所有 $L\le l\le R$ 的区间与 $[L,R]$ 交的长度和。$n,m\le 2\times 10^7$。

题解

即求 $L\le l\le R$ 中 $\sum \min(r,R)-l+1$。由于区间两两不包含,即 $l,r$ 均单调,于是询问对应一段区间内的区间。$(1-l)$ 的和容易前缀和,而 $\min(r,R)$ 在分界线两侧取不同值,找到分界线后也可前缀和算贡献。分界线只与 $R$ 有关,双指针预处理即可,这里可能要先桶排。时间复杂度 $O(n+m)$。弱化写不了。

  • 支配降维

可重复贡献时,可删掉无用元素。或错误答案一定被支配掉,此时不用管。

P11210 『STA - R8』强制在线动态二维数点

题意

平面上 $n$ 个点 $(x,y)$ 均满足 $x\ge y$,要求支持单点修改坐标,查询 $(l,l)$ 和 $(r,r)$ 两点形成的矩形内 $x-y$ 最小值。$n,q\le 5\times 10^5$。

题解

一个点会把其右下角的点支配掉,因为其答案更优且更容易被包含。这说明贡献点形成一段折线,然而这并没有什么用,因为修改时要支持删点,难以快速维护折线结构。但支配的性质还是要关注的。

考虑将 $(x,y)$ 放到 $x$ 上,并向 $(x,x)$ 连线,求端点在矩形内的最短连线。只有 $x$ 的限制是好做的,考虑去掉 $y$ 的限制。找到 $x\in [l,r]$ 的最小 $x$ 使得其对应的最大 $y\ge l$,则它会支配掉后面所有 $y\le l$ 的点,这时以该 $x$ 为左端点直接查询 $[x,r]$ 的 $x-y$ 最小值即可,答案不会出错。$x$ 可以线段树二分求,时间复杂度 $O(n\log n)$。

P11364 [NOIP2024] 树上查询

题意

给出一棵树,$q$ 次询问 $[L,R]$ 长度不低于 $k$ 的子区间中,区间内编号对应的所有点 LCA 深度的最大值。$n,q\le 5\times 10^5$。

题解

考虑区间 LCA 怎么求,显然可以取出 DFS 序最大和最小的两个点求 LCA,也可以求出所有 $i,i+1$ 的 LCA,这些 LCA 中深度最小的即为所求,可以用虚树证。于是设 $a_i$ 表示 $i,i+1$ LCA 的深度,区间 $[l,r]$ 的 LCA 深度即 $a$ 序列 $[l,r-1]$ 区间的最小值。

先特判掉 $k=1$ 的情况,用 ST 表求区间最值即可。剩余部分即求 $a$ 序列上 $[L,R-1]$ 长度不低于 $k-1$ 的子区间最小值的最大值。先画到平面上,考虑区间最小值的形式,每个 $(i,i)$ 点会向左上延伸出一个矩形,碰到比自己小的数时停止。求出该矩形后,可从其左上角向右下角无限延伸,每个点的答案是覆盖其的无限大矩形对应值的最大值。

考虑其实际意义的话,可以认为是找到了最小值不低于 $a_i$ 的极长区间 $[l_i+1,r_i-1]$,由于没有限制 $l\le i\le r$,所以可能会大于 $a_i$。之后求区间 $[s,e]$ 的最小值时,找到包含 $[s,e]$ 的所有极长区间,对其 $a$ 值取最大值即为答案,和平面上的推导相符。

最终要求 $[L,R-1]$ 内长度不低于 $k-1$ 的子区间最小值的最大值,显然长度更大的区间不优,于是只求平面上一条斜线的最大值。考虑对所有能贡献的极长区间求最大值,画到平面上可以拆成两个左上矩形和一个靠左的平行四边形,扫两遍就行,前者可以树状数组,后者只能线段树。复杂度 $\mathcal O((n+q)\log n)$。

10.01 思考题 众数杀手

给定一个由 $1,-1$ 构成的长为 $n$ 的序列,其中有 $x$ 个 $1$,默认 $x$ 远小于 $n$。定义序列权值为所有非负区间并的长度。

  • 可能的最大权值是多少?

考虑令 $1$ 之间的距离足够远,则每个 $1$ 及其两侧会在最终并中,总点数为 $3x$。若全聚到一起,发现总点数也是 $3x$。事实上上界即为 $3x$,因为每个 $1$ 最多使得合法区间拓展 $1$ 的长度,即使不重复贡献也只有 $3x$。最劣应该是隔一个放一个,大概是 $2x$。

  • 对于给定序列,输入 $x$ 个位置,如何在 $O(x\log n)$ 复杂度内求其权值?

考虑从左到右遍历每个位置,每次找左边未被标记的最近 $-1$ 并将其标记,之后清空所有标记,再从右到左做一遍,只有两轮中至少被打过一次标记的位置会产生贡献,将个数加上 $x$ 即为答案。

  • 对于给定序列,在 $n,x$ 同阶时,如何求区间和非负的区间个数?

对其求前缀和后,即求有多少 $i<j$ 且 $s_i\le s_j$ 的对 $(i,j)$,容易用树状数组等做到 $O(n\log n)$。然而注意到原序列只有 $1,-1$,因此可以直接用桶 + 指针实时维护合法的 $i$ 个数,容易做到线性。

  • 在 $x$ 远小于 $n$ 时,若上上个问题能 $O(x)$ 求解,是否也能 $O(x)$ 求解上个问题?

只把上上个问题中不超过 $3x$ 个位置拿出来,对每个原序列上的连续段分别做上个问题即可,总时间复杂度显然为 $O(x)$。

P4062 [Code+#1] Yazid 的新生舞会

题意

给定一个序列 $a$,求有多少个区间存在绝对众数。$n\le 5\times 10^5$。

题解

枚举绝对众数为 $t$,令 $b_i=(-1)^{[a_i\ne t]}$,则转化为求 $b$ 有多少个子区间和为正。可以直接套用上面的几个问题求。现在需要快速找到 $3x$ 个位置,考虑直接使用序列并查集,预处理 $l_i=i-1,r_i=i+1$,之后直接查询两边首个未标记位置即可。

由于复原 $l,r$ 数组和清空标记只需操作拿出来的 $3x$ 个位置,于是单次复杂度也是 $O(x)$ 的。由于 $\sum x=n$,总复杂度为 $O(n)$,然而对拿出来的位置操作前需要对其排序,可能不得不加上一个排序的 $O(n\log n)$ 复杂度,也成为了复杂度瓶颈。

CF1446D2 Frequency Problem (Hard Version)

题意

给定一个序列 $a$,求众数不唯一的最长子区间长度。$n\le 2\times 10^5$。

题解

考虑全局众数 $x$,若有多个则答案为 $n$,否则一定存在最优区间的众数包含 $x$。若众数不包含 $x$,则可以不断扩张该区间直到 $x$ 和某数出现次数相同。同时可将众数条件弱化为 $x,y$ 在区间内出现次数相同,显然这可以取到答案,而这样求到的不合法区间($x,y$ 不为众数)一定不优,可以扩张直到 $x$ 与原众数出现次数相同。

于是问题变为固定 $x$,对所有 $y\ne x$ 求 $x,y$ 出现次数相同的最长子区间长度。将 $x$ 看成 $-1$,$y$ 看成 $1$,即求最长的和为 $0$ 子区间。仿照上题思路找出所有有效位置,再用前缀和相等判断即可。有一些细节,比如并查集要建在所有 $x$ 上之类。总之时间复杂度 $O(n\log n)$,还在排序。

10.02 树上问题

主要是 LCA 相关性质。

CF1062E Company

题意

给定一棵树,$q$ 次询问从 $[l,r]$ 中删去一个点后,剩余点 LCA 深度的最大值。$n,q\le 10^5$。

题解

点集的 LCA 与 DFS 序最大和最小两点的 LCA 相同,因此只有删这两个点之一才可能使 LCA 深度增大。维护区间 DFS 序最大最小次大次小值,判断删哪个更优即可。ST 表维护区间最值,LCA 随便求一下,复杂度 $\mathcal O((n+q)\log n)$。

CF176E Archaeology

题意

给定一棵树,动态维护一个点集,需要支持增删,查询当前点集形成虚树的边权和。$n,q\le 10^5$。

题解

对于大小为 $k$ 且按 DFS 序排序的点集 $S$,其虚树边权和为 $\frac{\sum_{i=0} d_{S_i,S_{(i+1)\bmod k}}}2$,即相邻两点距离之和的一半,正确性比较显然。于是按 DFS 序维护当前点集,插入时跟前驱后继更新一下即可,复杂度 $\mathcal O(q\log n)$。

P6071 『MdOI R1』Treequery

做法应该类似上一题,找出 DFS 序上的前驱后继即可,强制在线要主席树。之后应该会做。

10.03-10.04 计数

  • 二项式反演

CF995F Cowmpany Cowmpensation

题意

给出一棵 $n$ 个点的树,要求填入 $[1,k]$ 内的整数,且满足每个的值不大于其父亲,求方案数。$n\le 3000,k\le 10^9$。

题解

有一个显然的 DP,设 $f_{u,i}$ 表示以 $u$ 为根的子树 $u$ 点填 $i$ 的方案数,有 $f_{u,i}=\prod_{v}(\sum_{j\le i}f_{v,j})$,加上前缀和优化后是 $\mathcal O(nk)$ 的。然而注意到 $n$ 个点最多只会填 $n$ 种值,于是考虑求 $g_i$ 表示一共填 $i$ 种值的方案数,答案即 $\sum_i {k\choose i}g_i$。

仍然进行 $f$ 的 DP,且限制第二维不超过 $n$。此时显然有 $g_1=f_{1,1}$,之后有 $g_i=f_{1,i}-\sum_{j\lt i} {i-1\choose j-1} g_j$,这样就求出了 $g$。至于 $k\choose i$ 这种 $k$ 很大 $i$ 较小的组合数,可以预处理 $k$ 的前 $n$ 次下降幂,总复杂度 $\mathcal O(n^2)$。

  • min-max 容斥

[ABC242Ex] Random Painting

题意

给出 $m$ 个在 $[1,n]$ 内的区间,保证每个位置被至少一个区间包含。每次随机取出个区间,并标记区间内的所有位置,求期望取多少次后所有位置均被标记。$n,m\le 400$。

题解

设 $t_i$ 表示 $i$ 位置第一次被标记的时间,求 $E(\max t_i)$。直接考虑 min-max 容斥,变成了 $\sum_{S}(-1)^{\left|S\right|+1}E(\min_{i\in S} t_i)$。这里 $E(\min_{i\in S}t_i)$ 就比较好算了,根据定义只需求出内部有 $S$ 中位置的区间数量 $c$,则每次取都有 $\frac cm$ 的概率覆盖到 $S$ 内的位置,期望次数为 $\frac mc$。

于是对所有 $c$ 求恰有 $c$ 个区间内有 $S$ 中位置的 $S$ 系数和,直接 DP,设 $f_{i,j}$ 表示最后一个位置选在 $i$,且目前有 $j$ 个区间合法的带容斥系数方案数。初值为 $f_{0,0}=-1$,转移为 $f_{k,j}\rightarrow f_{i,j+\sum[k\lt l\le i\le r]}$,系数为 $-1$。 转移中加的量可以提前二维前缀和预处理,总复杂度为 $\mathcal O(n^2m)$。

  • 其他容斥

LOJ3395. Yet Another Permutation Problem

状态数的级别需要用生成函数证,之后还得学学。

[ABC236Ex] Distinct Multiples

P8329 [ZJOI2022] 树

P10591 BZOJ4671 异或图

  • 自动机

YDRS005E. 将那朵云彩也跨越

  • 其他计数类 DP

P10547 [THUPC 2024 决赛] 排列游戏

[ARC163D] Sum of SCC

[AGC013D] Piling Up

  • 形式幂级数与生成函数

P4365 [九省联考 2018] 秘密袭击 coat

[ABC241Ex] Card Deck Score

QOJ8543 Periodic Sequence

  • 杂题

[ABC288Ex] A Nameless Counting Problem

10.05 构造

这部分没有收入做题计划,只记了题号。

  • 鸽巢原理

CF1450C2 Errich-Tac-Toe (Hard Version)

题意

给出一个 $n\times n$ 网格图,其中 $k$ 格非空,每格为 $0$ 或 $1$。可单点修改至多 $\lfloor\frac k3\rfloor$ 次,要求横竖相邻三个元素不全相等,构造方案。$n\le 300$。

  • DFS 树

P5811 [IOI 2019] 景点划分

题意

给定一张图,要求将其划分成大小为 $a,b,c$ 的三部分,使得至少两个部分连通。$n\le 10^5,m\le 2\times 10^5$。

CF1205D Almost All

题意

给定一棵树,要求每个点分配非负整数点权,使得 $\forall x\in[1,\lfloor\frac{2n^2}9\rfloor]$,树上存在点权和为 $x$ 的路径。$n\le 5\times 10^5$。

UOJ670 【UNR #5】获奖名单

题意

给定 $n$ 个长不超过 $2$ 的字符串,要求任意翻转后拼成一个回文串,构造方案。$n\le 5\times 10^5$。

CF1270G Subset with Zero Sum

题意

给定 $a$,满足 $i-n\le a_i\le i-1$,求一个和为 $0$ 的子集。$n\le 5\times 10^5$。

题解

老题了,考虑由 $i$ 向 $i-a_i$ 连边,注意到该图 $n$ 点 $n$ 边,一定是内向基环树森林。又注意到每个环上 $i-a_i$ 的和与 $i$ 的和相等,于是 $a_i$ 的和为 $0$,找到图中任意一个环即为答案,复杂度 $\mathcal O(n)$。

当然之后 LCA 又讲了一遍这个题,是用前缀和和抽屉原理解决的。

  • 归纳

[ARC122E] Increasing LCMs

题意

给定 $a$ 序列,重排使得前缀 LCM 严格递增。$n\le 100,a_i\le 10^{18}$。

CF1637G Birthday

题意

初始存在 $[1,n]$ 的 $n$ 个数,每次操作取出 $x\ge y$,将其变为 $x+y,x-y$ 两数,希望最终数字全相同且尽可能小,操作次数不超过 $20n$。$\sum n\le 5\times 10^4$。

  • 杂题

P6948 [ICPC 2018 WF] Single Cut of Failure

题意

给出一个矩形,存在若干条线段,均满足端点在边框上且不与边框重合。求多少条满足该限制的线段可切断所有给定线段。$n\le 10^6$。

CF1658F Juju and Binary String

题意

给定长为 $n$ 的序列,构造尽可能少的长度和为 $m$ 的子串,使得其中 $1$ 所占比例与原序列相同。$m\le n\le 2\times 10^5$。

CF1622F Quadratic Set

题意

给定 $a_i=i!$,要求选出一个尽可能大的子集,使得其乘积为完全平方数。$n\le 10^6$。

【学习记录】网络流

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

本文大部分内容借鉴自该专栏,也感谢曹神给推了这么牛的讲解。

以下所有最大流和费用流(最大/最小费用最大流)均可使用 Dinic 求解,我只会这个

二者取一式问题

每个元素有两种选择 $A,B$,分别有 $a_i,b_i$ 的收益。另有整体收益为某些元素均选 $A$ 时收益 $c$,或某些元素均选 $B$ 时收益 $d$。建模方式为连边 $(S,i,a_i)$ 和 $(i,T,b_i)$,定义割中保留的边表示选。整体收益建一个新点 $t$,选 $A$ 则连边 $(S,t,c)$ 和 $(t,x,\infin)$,选 $B$ 则连边 $(t,T,d)$ 和 $(x,t,\infin)$。该图的边权和减去最小割即为答案,容易发现这是对的,因为 $\infin$ 边不会被割,若某限制中有选错的,则收益边必须被割。最小割可用最大流求解,板题提交记录

P2057 善意的投票

本题中要求最小化代价,考虑直接将代价作为流量,并定义割掉表示选,这样直接求最小割得到最小代价。考虑如何刻画 $(x,y)$ 选择不同时 $1$ 的代价,直接连 $(x,y,1),(y,x,1)$ 两条边即可,画图可以发现若两点割掉的边不同,则必定割两条新边中的一条。因此这样是对的,直接求最小割即为答案,提交记录

本题也可以转化成收益做,即转化为求最大的不冲突数。那么每对朋友需要新建两个点表示收益,求出最大值后用 $n+m$ 减去即为答案,提交记录,由于点数较多,比上一种略慢一些。

WyOJ342 捆绑销售

求分数最大值考虑二分,则要求 $\frac{(\sum a_i)^2}{\sum a_i^2}\ge k$,移项拆式子可得 $\sum_{i<j} 2a_ia_j+\sum_i(1-k)a_i^2\ge0$,因此求左式最大值即可。显然可以建模到网络流图上,前式是整体收益,后式必为负,因此提前求和计入答案,并转化成不选的正收益。问题在于题目中还有捆绑限制,即选 $x$ 后必选 $y$,因此需求最大权闭合子图,方式为直接连边 $(x,y,\infin)$,该边无法被割,因此不能选 $x$ 却不选 $y$,可以求出正确答案。网络流需要浮点数流量,有一些细节,提交记录

无源汇上下界可行流

考虑先将所有边的流量设为下界,则每条边剩余流量为上下界之差,以此可建出差网络。然而此时不一定满足流量守恒,需要用差网络上的流量使其守恒。

具体地,设 $w_u$ 表示流量均为下界时 $u$ 点的净流入量,若为负则表示有 $-w_u$ 的净流出量。以 $w_u>0$ 为例,此时差网络上需要 $u$ 的净流出量为 $w_u$,以使得总流量守恒。因此建立源点 $S'$,并由源点向 $u$ 连流量为 $w_u$ 的边,则差网络上该边流满且 $u$ 点流量守恒时,原网络上流量也守恒;同理,若 $w_u<0$,则由 $u$ 向汇点 $T'$ 连流量为 $-w_u$ 的边即可。此处本质上是将流量下界所带来的净流量用新源汇等效替代了。

此时以 $S',T'$ 为源汇跑最大流,若所有代表净流量的边均满流,则目前流量与流量下界之和即为一组可行流;否则原网络无可行流。具体判断时由于源点流出量与汇点流入量相等,只需判断源点出边是否均满流即可。代码

有源汇上下界可行流

只需加入一条由 $T$ 到 $S$,流量为 $\infin$ 的边,即可转化为等价的无源汇网络,可以直接做。

有源汇上下界最大流

先求出一组可行流,此时新边 $(T,S)$ 的流量即为目前流量。考虑去掉该边和 $S',T'$,重新以 $S,T$ 为源汇在残量网络上跑最大流,答案即为两个流量的和。实现上由于有解时 $S',T'$ 所连边均已流满,无需处理;同时可行流 $f$ 产生了一条 $(S,T,f)$ 的反悔边,而 $(T,S)$ 不会被访问,因此不进行任何处理时,残量网络上 $S,T$ 为源汇的最大流即为答案。代码

有源汇上下界最小流

与最大流类似,只是求出可行流后要以 $T,S$ 分别为源汇跑最大流,并从可行流中减去得到答案,可理解为把可退流均退掉了。此处没有简便实现,需要清掉边 $(T,S)$ 并累加答案。代码

P5192 Shoot the Bullet

以每天为左部点,每位少女为右部点,由源点 $S$ 向左部点连 $[0,D_i]$ 的边,由右部点向汇点 $T$ 连 $[G_x,\infin]$ 的边,左部点和右部点间连 $[L,R]$ 的边,求有源汇上下界最大流即为答案。提交记录

无源汇上下界费用流

所求为费用达到最值的可行流,做法也与可行流类似,所建新边费用均为 $0$,直接跑出差网络的费用流即为答案。

P4043 支线剧情

据题意建边,设流量为途径次数,所求即为最小费用。由于每条边均需被覆盖至少一次,这些边流量限制为 $[1,\infin]$,费用为 $t$;同时任意点都可直接回到 $1$ 号点,因此每个点都向 $1$ 号点连 $[0,\infin]$,费用为 $0$ 的边。该网络的无源汇上下界最小费用流即为答案。提交记录

有源汇上下界费用流

同可行流一样,只需加入一条由 $T$ 到 $S$,流量为 $\infin$,费用为 $0$ 的边,即可转化为等价的无源汇网络。注意此时直接求出的是可行流的费用最值,而对流量没有保证。若还要求流量最大/最小,还需要像不带费用时一样在残量网络上跑费用流并累加才行。

P7173 有负圈的费用流

考虑清除所有 $c<0$ 的负边 $(u,v,f,c)$,方式为将其强制流满,即令其流量限制为 $[f,f]$,并加入反边 $(v,u,f,-c)$ 用于反悔。非负边流量限制为 $[0,f]$,费用不变。对该网络求有源汇上下界最小费用流,可得到费用最小的可行流。为了达到流量最大,还需在残量网络上以 $S,T$ 为源汇跑费用流,并将所得流量和费用累计入答案。当然这里与有源汇上下界最大流一样,最大流量也可以不处理直接得到。提交记录

最小费用流的对偶

最小费用流可表示为 $\min\sum g_{u,v}c_{u,v}$,限制为 $g_{u,v}\le f_{u,v}$,且 $\forall x,\sum g_{u,x}-\sum g_{x,v}=b_x$。其中 $f,c$ 分别为流量限制和费用,$g$ 为实际流量,$b$ 为某点要求的净流入量,为负则绝对值为净流出量。

分别以 $d_{u,v},p_u$ 为对偶变量时,对偶得到 $\max \sum-d_{u,v}f_{u,v}-\sum b_up_u$,限制为 $-d_{u,v}+p_v-p_u\le c_{u,v},d_{u,v}\ge 0$。由于 $f$ 为整数,$d$ 越小越好,因此 $d_{u,v}$ 会取 $\max(0,p_v-p_u-c_{u,v})$。据此整理所求式可得 $-(\min(\sum\max(0,p_v-p_u-c_{u,v})f_{u,v}+\sum b_up_u))$。因此若得到如此形式的式子,可转化成费用流求解。

P3337 防守战线

设 $p_i$ 为所修塔数的前缀和,即前 $i$ 个位置上修塔总数。转化可得所求为 $\min\sum(c_i-c_{i+1})s_i$,限制为 $p_i-p_{i+1}\le 0,p_{l-1}-p_r+d\le0$。考虑将 $x$ 不大于 $0$ 的限制转化为 $\infin\times \max(0,x)$ 放入 $\min$ 式中,即可得到上述形式的式子。

根据变量含义建出网络流图,以下 $(f,c)$ 表示流量上限为 $f$,费用为 $c$。需要由 $i+1$ 向 $i$ 连 $(\infin,0)$ 的边,由 $r$ 向 $l-1$ 连 $(\infin,-d)$ 的边。另有 $b_i=c_{i}-c_{i+1}$,该净流量要从源汇处取得,即若 $b_i>0$,由 $S$ 向 $i$ 连 $(b_i,0)$ 的边;否则由 $i$ 向 $T$ 连 $(-b_i,0)$ 的边。根据上述对偶,该网络最小费用最大流的费用即为答案的相反数。

注意到该网络中费用非正,存在负圈,因此需使用有负圈的费用流求解,这也是我去学上述内容的出发点。本题数据范围较大,费用流只能通过 70 分,提交记录。另外注意到转化后的网络中不存在负边,可以用 Dijkstra 代替 SPFA,然而过得更少了。想通过本题可能需要使用原始对偶或单纯形,然而这不是本文所讨论的内容,同时我不会也不想学,不再叙述。

【学习记录】数据结构

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

二轮省集发现自己啥都不会,决定学点新东西,于是就学了。事实上拖到三轮之后很久才写完

树状数组上倍增

不难但我刚学。树状数组上 $b_i$ 代表原数组 $[i-w(i)+1,i]$ 的和,其中 $w(i)$ 为 $i$ 的 lowbit 值。因此枚举 $k$ 从 $\lfloor \log n\rfloor$ 到 $0$,初始指针 $p$ 为 $0$。每次查询当前 $[p+1,p+2^k]$ 之和 $b_{p+2^k}$ 是否达到目前 $x$。若未达到则将 $x$ 减去区间和,并更新 $p\leftarrow p+2^k$,否则不更新。最终 $p$ 即为前缀和小于 $x$ 的最大位置。使用 CF1070C 进行了测试,所用时间大概是线段树二分二分 + 树状数组的一半。

树状数组维护区间和

考虑维护差分数组 $d_i=a_i-a_{i-1}$,区间 $[l,r]$ 加上 $x$ 即为 $d_l=d_l+x,d_{r+1}=d_{r+1}-x$,容易修改。查询时差分成前缀和,有前缀和 $s_k=\sum_{i=1}^k a_i=\sum_{i=1}^k\sum_{j=1}^i d_j$,交换求和号得到 $s_k=\sum_{j=1}^k(n-j+1)d_j=(n+1)\sum_{j=1}^k d_j-\sum_{j=1}^kjd_j$,用树状数组分别维护 $d_j,jd_j$ 前缀和即可,代码。若要查询 $ia_i$ 的区间和同样可推得 $s_k=\sum_{j=1}^k\sum_{i=j}^k id_j$,等差数列求和得 $s_k=\frac 12\sum_{j=1}^ k[(k^2+k)d_j+jd_j-j^2d_j]$,需要额外维护 $j^2d_j$ 的前缀和。

历史和

需要支持区间加,查询区间历史和。历史和定义为 $h_i$ 的区间和,初始 $h_i=a_i$,每次操作之后均更新所有 $h_i\leftarrow h_i+a_i$。以下做法时间复杂度均为 $O(n\log n)$,但常数上有较大差异。

Sol.1

考虑使用矩阵维护,设 $l,s,h$ 分别为区间长度,区间和和区间历史和,则当区间加 $x$ 时, $$ \begin{bmatrix} l &s&h\end{bmatrix}\begin{bmatrix} 1&x&0\\ 0&1&0\\ 0&0&1\end{bmatrix}=\begin{bmatrix} l &s+lx&h\end{bmatrix} $$ 更新一次历史和时, $$ \begin{bmatrix} l &s&h\end{bmatrix}\begin{bmatrix} 1&0&0\\ 0&1&1\\ 0&0&1\end{bmatrix}=\begin{bmatrix} l &s&h+s\end{bmatrix} $$ 因此直接使用线段树维护矩阵,矩阵乘法维护标记即可,常数较大,代码

Sol.2

观察上个做法中的矩阵,注意到均为上三角,且对角线均为 $1$,有 $$ \begin{bmatrix} 1 &a&b\\ 0&1&c\\ 0&0&1\end{bmatrix}\begin{bmatrix} 1&x&y\\ 0&1&z\\ 0&0&1\end{bmatrix}=\begin{bmatrix} 1&a+x&b+y+az\ &1&c+z\&0&1\end{bmatrix} $$ 因此只记录 $x,y,z$ 三个数即可表示矩阵,合并方式即上式,常数会小很多,代码

Sol.3

考虑拆每个修改的贡献。具体地,若在第 $t$ 次操作时给某位置加了 $x$,则第 $T$ 次操作询问时,该修改的贡献为 $(T-t)x=xT-xt$,是关于 $T$ 的一次函数,因此分别维护两个系数的区间加、区间和即可。线段树树状数组,树状数组做法在提交时为本题最优解。

Sol.4(25.10.28 补充)

lxl 讲了这个,所以记一下。考虑标记序列,其由若干加标记和历史和标记构成。相邻相同标记可以直接合并,于是两种标记交替出现。尝试交换标记,发现可以将历史和标记全扔到最后,这会导致历史和多加了一些加标记的值,再开一个标记变量记录一下就行。

具体地,标记为 $(t,c,h)$,表示先加 $t$,再累加 $c$ 次历史和,再给历史和加上 $h$。标记的合并为 $(t_1,c_1,h_1)+(t_2,c_2,h_2)=(t_1+t_2,c_1+c_2,h_1+h_2-c_1t_2)$。信息为 $(s,c,h)$,分别表示当前和,区间长度和历史和,信息的合并是容易的,信息与标记合并为 $(s,c,h)+(t',c',h')=(s+t',c,h+c(c's'+h')+c's)$,直接上线段树即可,常数大概跟矩阵拆成三个数差不多,提交记录

历史最值:P4314 CPU 监控

需要支持区间加、区间赋值以及求区间最大值、区间历史最大值。令区间加标记为 $ta$,考虑额外维护一个标记 $tb$,表示未下放标记的历史最大值。给 $x$ 加标记时先尝试用 $x+tb$ 更新历史最值,再更新 $x\leftarrow x+ta$。标记的合并也一样,如将 $(ta',tb')$ 合并到 $(ta,tb)$ 上时,先尝试用 $ta+tb'$ 更新 $tb$,再更新 $ta\leftarrow ta+ta'$。

加上区间赋值时,若无历史最值要求,则赋值标记 $ca$ 和加标记 $ta$ 不会同时存在,即赋值时会清空加标记,区间加时若存在赋值标记则更新赋值标记,而不是添加加标记。此时为了求历史最值,也需额外维护一个标记 $cb$,表示未下放覆盖标记的历史最大值。此时赋值只清空 $ta$ 而保留 $tb$,因为历史最值还需要更新;区间加时若存在 $(ca,cb)$ 同样更新 $(ca,cb)$ 即可,合并方式同上。注意为了正确地用 $tb$ 更新历史最值,在 pushdown 时要先下放 $(ta,tb)$,再下放 $(ca,cb)$。时间复杂度 $O(n\log n)$。提交记录

区间最值操作、区间历史最值:P6242 线段树 3

需要支持区间加,区间对一个数取 min 以及求区间和、区间最大值、区间历史最大值。若无 checkmin 操作,可直接用上题做法维护。考虑到对 $x$ 取 min 是把大于 $x$ 的数减到了 $x$,然而不同数所减值也不同,难以用标记统一维护。因此再维护区间次大值 $cmx$,只在 $cmx\le x< mx$ 时用标记记录 $mx$ 的变化,标记形式为记录历史最值的两个值 $(ta,ma)$,否则直接暴力递归到子节点中。

此时再用 $(tc,mc)$ 标记记录非最大值的情况。区间加时两者都合并上 $(x,x)$,checkmin 到合法节点时只给最大值标记合并上 $(x-mx,x-mx)$ 即可。标记下传时讨论子节点最大值是否是整个区间最大值,若是则分别用 $(ta,ma),(tc,mc)$ 更新两组标记,否则均用 $(tc,mc)$ 更新。具体地,先取 $X=\max(mx_l,mx_r)$,再用 $X$ 来判断 $mx_l,mx_r$ 是否为最大值。这里不能直接用父亲节点最大值 $mx_u$,因为此时父亲节点可能已被修改,而要判断的是最大值是否为修改前的区间最大值。

该算法正确性没有问题,时间复杂度单点修改时为 $O((n+m)\log n)$,可以使用不同数的个数证明,即若暴力递归,则有 $x<cmx$,本次操作后该节点不同数个数会减少,由于线段树每层都只有 $O(n)$ 个不同的数,共 $O(n\log n)$ 个,单点修改时只会增加 $O(m\log n)$ 个,总递归次数得到保证。至于本题的区间加我不会证,但跑出来看着挺对的,至少不超过 $O(n\log n+m\log ^2 n)$。论文里还提到可能比这更低,也有讨论说不一定是真的,可以自己去看。

P10639 最佳女选手

需要支持区间加,区间对一个数取 min/max 以及求区间和、区间最大最小值。类似上题,在每个节点上维护区间最大、次大、最小、次小值,再分别维护所有值、最大值、最小值的加标记。最值操作时同样只在单值修改时打标记修改,否则暴力向下递归。需要注意节点内只有单个值 / 两个值时要注意最值的更新,有点细节。时间复杂度同样不高于 $O(n\log^2 n)$,同样不会证提交记录

树套树:P3380

或许不怎么考,但本着练码力的目的还是写了。

注意到所有操作均可用平衡树或权值数据结构完成,这时加入区间限制,考虑使用树套树,即在外层数据结构每个节点上开一个内层数据结构,查询时在外层数据结构上找到所查询区间,用这些内层数据结构进行查询即可。

对于本题,外层可使用线段树。内层若使用平衡树,则需对其进行合并,总复杂度会达到 $O(m\log ^3n)$,且我不想写平衡树。因此内层使用动态开点权值线段树,这样也能保证空间复杂度为 $O((n+m)\log^2n)$。找出 $O(\log n)$ 棵树后,对这些树同时求区间和或二分即可。注意若外层为树状数组则需要差分,需要记录贡献系数。

另外对于前驱后继查询,除了线段树上二分之外,外层线段树时可直接额外开 $n$ 个 set,查询时多次询问取最值。然而外层树状数组时需差分,不能用 set 简便操作。然而 $x$ 的前驱即 $kth(rk(x)-1)$,后继即 $kth(rk(x+1))$,因此只需要实现区间和和二分出第 $k$ 小即可,常数也没大多少。时间复杂度 $O((n+m)\log ^2n)$,提交记录

动态树:P3690

要求维护带点权的森林,支持连边、删边、单点修改,查询路径异或和。LCT 是对树进行实链剖分得到的,钦定每个点连向其儿子的边中某一条为实边。对每条实链以深度为键值建出 Splay 后,再以原树中链头父亲为 LCT 中 Splay 根节点的父亲。注意这样跨实链的边有“认父不认子”特点,该父节点的子节点是 Splay 结构,而不记录跨实链的儿子,可以以此判断某点是否为 Splay 的根。下面是基本操作:

  • access(x):在 LCT 中将 $x$ 到根的路径变成一条完整实链。

由 $x$ 跳到根,每次先将 $x$ splay 至当前 Splay 的根,然后将其右儿子赋为上个 $x$,再令 $x\leftarrow f_x$。这样使得路径上所有边均变为实边,且最初 $x$ 的右儿子为 $0$,即已经是实链链底,这样就实现了 access 操作,注意过程中要进行 pushup 更新。

  • makeroot(x):将 $x$ 变为其所在树的根节点。

考虑先 access(x),这样 $x$ 变成了实链链底。然后将其 splay 至根,其右儿子一定为空。这时将整棵 Splay 翻转,就让其变成了整棵树的根。为了实现翻转操作需要使用懒标记。

  • findroot(x):查询 $x$ 所在树的根节点。

先 access(x) 并 splay(x) 到根,然后从 $x$ 一直跳左儿子得到中序遍历最前的点即为根。向下跳前时需要下传懒标记,且找到根节点后要将其 splay,以保证依赖势能的复杂度。另外若不 splay 在模板题中会出现神秘错误,我还没想清楚是为什么。

  • split(x,y):将 $x,y$ 之间的路径变为一条实链(一棵 Splay)。

容易想到 makeroot(x),access(y) 即可实现,为了保证复杂度需要 splay(y),同时这样也使得 $y$ 变为根,该路径即为 $y$ 的整个子树。

  • link(x,y):若两点不连通,增加一条 $x,y$ 之间的边。

先 makeroot(x),这时若 findroot(y) 不为 $x$ 则两点不连通,由于 $x$ 已为根,直接将其父亲赋为 $y$ 即可,不会破坏实链剖分的结构。

  • cut(x,y):若两点之间有边则将其断开。

先 makeroot(x),这时需要 $y$ 所在树根为 $x$,$x$ 为 $y$ 父亲且 $y$ 没有左儿子,三个条件均满足时 $x,y$ 相连,$y$ 为 $x$ 右儿子。将 $x$ 右儿子和 $y$ 父亲均清空即可断边,注意此时要进行 pushup 更新。

其他细节:rotate 不能跨虚边操作,只在跨实边时更新儿子;splay 前要把该 Splay 内根到该节点的所有点依次 pushdown,保证标记正确。模板题使用上述操作即可实现,提交记录。时间复杂度均摊 $O(q\log n)$,我不会证。

P1501 Tree II

维护一棵树,支持删边再加边,路径加,路径乘以及求路径和。删边和加边操作与模板相同,需要维护的是修改操作。这里类似线段树 2,设计加标记和乘标记,路径乘时同时给两个标记乘即可。需要注意的是 LCT 上要同时更新子树值和单点值,才能保证答案正确。是比较板的懒标记 LCT,时间复杂度 $O(q\log n)$,提交记录

全局平衡二叉树

可以认为是静态的 LCT 结构,要求树高为 $O(\log n)$ 级别,以方便进行点到根的路径操作。具体做法为先重链剖分,每条重链以深度为键值建二叉搜索树,重链间以虚边连接,同样“认父不认子“。建二叉搜索树时以虚子树总点数为点权,以带权重心为根并递归到两边建子树。这样重链内部每次向上跳会让子树大小翻倍,而每个点到根的路径只有 $O(\log n)$ 条轻边,因此总树高为 $O(\log n)$。

这时点 $x$ 到根的路径可在 GBT 上跳到根得到,开一个布尔变量 $v$ 记录目前是否在所求路径上。跳父亲时若 $x$ 为父亲左子树,则父亲深度比 $x$ 大,不在路径上;为右子树或跨过轻边时父亲深度均比 $x$ 小,还在路径上,因此跳之前设 $v=[x\ne lc_{f_x}]$ 即可。访问时 $v=1$ 的所有点 $u$ 及其左子树的并为原树中 $x$ 到根的路径,可以使用子树标记维护。

P4211 LCA

先将询问差分成前缀,转化为给出 $x,k$,求 $\sum_{i=1}^k w(i,x)$,其中 $w(i,x)$ 表示 $i$ 和 $x$ 的 LCA 深度。注意到两点 LCA 深度即为两点到根路径交的长度,因此对所有 $i$ 到根的路径加 $1$ 后,查询 $x$ 到根的路径和即为所求。

因此需要支持某点到根路径加,求某点到根路径和。容易使用树剖做到 $O(q\log ^2n)$,这是使用线段树的代码 A 和使用树状数组的代码 B。然而某点到根的路径显然可以使用 GBT,用懒标记维护子树加即可,时间复杂度 $O((n+q)\log n)$,代码 C。如果使用标记永久化技巧,可以避免从根 pushdown 一遍的常数,代码 D。最终运行时间为 $D<B<C<A$,中间两种差距较小,所以树状数组真王朝了

P4719,P4751 动态 DP

不带修是简单树形 DP,设 $f_{i,0/1}$ 表示 $i$ 子树内是否选 $i$ 点时的最大点权和,转移为 $f_{u,0}=\sum\max(f_{v,0},f_{v,1}),f_{u,1}=\sum f_{v,0}+a_u$,其中 $v$ 为 $u$ 子节点。考虑若修改点权,则其到根路径上所有点的 DP 值均需要更新,然而暴力跳到根复杂度难以接受,需要快速修改。

考虑用矩阵刻画 DP 转移,从而让 DP 过程变成矩阵乘法,方便单点修改。由于要求最优化,使用 max+ 矩阵,即 $c_{i,j}=\max(a_{i,k}+b_{k,j})$ 的矩阵维护。为了快速更新,先进行重链剖分,再设 $g_{i,0/1}$ 表示不考虑 $i$ 的重儿子时的 DP 值,则有 $f_{u,0}=g_{u,0}+\max(f_{son_u,0},f_{son_u,1}),f_{u,1}=g_{u,1}+f_{son_u,0}$。此时便有: $$ \begin{bmatrix} f_{son_u,0} & f_{son_u,1}\end{bmatrix}\begin{bmatrix} g_{u,0}&g_{u,1}\\g_{u,0}& -\infin\end{bmatrix}=\begin{bmatrix} f_{u,0}&f_{u,1}\end{bmatrix} $$ 因此在每个点上维护上式中的矩阵,某点的 DP 值即为其所在重链链底到该点的路径矩阵乘积。单点修改时 $g_{u,1}$ 会改变,从而其所在重链链头 DP 值改变,又使得跨过轻边后的父亲 $g$ 值改变。因此向上跳 $O(\log n)$ 条重链,每次修改其对下一条重链的影响即可。使用线段树维护矩阵乘积是 $O(q\log ^2n)$ 的,不卡常只能通过 $n,q\le 10^5$ 的 P4719,提交记录。可使用 GBT 维护,只在跳轻边时更新,复杂度 $O(q\log n)$,提交记录,可以通过加强版

并查集

别问为什么会在这里,因为我之前不咋懂而且下面要用

之前我甚至没写过合并优化

按秩合并 / 启发式合并

合并时将高度小的并查集合并到高度大的,或是将大小小的合并到大小大的,两种做法的单次复杂度均为 $O(\log n)$。如果再加上路径压缩,复杂度会降到总共 $O(q\lpha(n))$,使用大小启发式合并的提交记录。虽然单独使用路径压缩同样也是 $O(q\log n)$,然而其会破坏树的结构,在某些情况下只能优化合并来保证复杂度。

可撤销并查集

特殊情况来了,要求支持撤销最后一次有效合并。由于路径压缩会改变树的形态,难以撤销,只能优化合并。开一个栈记录所有被修改 $f$ 值的 $x$,要撤销时拿出栈顶 $x$ 直接改回 $f_x=x$ 即可,还要将变化的 $s$ 值修改回去。这里按大小启发式合并更容易复原,因此采用这种写法。时间复杂度 $O(q\log n)$,提交记录

扩展域并查集:P1525 关押罪犯

其实比较简单,在本题中即给每个元素新开一个点 $n+i$,令 $i,n+i$ 分别表示 $i$ 点放到两个不同监狱中。把关系按影响力从大到小排序后依次处理,每次先分别合并 $u,n+v$ 和 $v,n+u$,若此次合并导致 $u,n+u$ 或 $v,n+v$ 在同一集合内,则已经出现冲突,答案为该关系的影响力。并查集操作与模板相同,复杂度可以做到 $O(q\lpha(n))$,提交记录

线段树分治

若操作在某个时间段内有效,可以离线后在时间轴上建线段树,并把操作拆到 $O(\log V)$ 个线段树节点上。之后遍历整棵线段树,进入某节点时执行所有该节点上的操作,遍历完子树后回溯时将操作撤销,在每个叶子节点上统计对应时刻的答案即可。

P5787 二分图

每条边在一段时间内存在,询问每个时刻整个图是否为二分图。二分图判断可以使用扩展域并查集维护,每条边都变成了两次合并操作。使用线段树分治,将其放到 $O(\log n)$ 个节点上。遍历时若在某点出现冲突,则其内部所有时刻均非法,可以直接回溯;若到叶子节点仍未冲突,则该时刻合法。回溯时用栈维护可撤销并查集即可实现,总时间复杂度为 $O(m\log k\log n)$,为操作数乘上单次操作复杂度,提交记录

CF1814F Communication Towers

点的存在不好处理,不妨转化为边存在,即边 $(u,v)$ 在 $[\max(l_u,l_v),\min(r_u,r_v)]$ 内的时刻存在,可以像上题一样用可撤销并查集维护连通性。统计答案需要在每个时刻给 $1$ 所在的连通块打标记,考虑设 $w_i$ 表示 $i$ 点与 $1$ 连通的时刻数量。每个时刻给 $1$ 所在连通块根节点标记加 $1$,$x$ 合并到 $y$ 时先给 $w_x$ 减掉目前 $w_y$,撤销该操作时给 $w_x$ 加上此时的 $w_y$,从而差分得到跟 $y$ 连通时的实际贡献。最后所有边均消失,每个点独立,输出所有 $w_x>0$ 的 $x$ 即为答案。时间复杂度 $O(m\log V\log n)$,提交记录

25.06-三轮省集模拟赛题解

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

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

由于水平有限,只补了一部分题,因此只有这部分题解。

D1T1 人渣的本愿

题意

给定一棵树,初始每个点信息为 $(0,0)$,需要支持单点查询。修改为对 $x$ 到根路径上所有点 $u$ 操作,若 $(a_u,b_u)$ 中 $a_u\ne c$ 则将其修改为 $(c,z)$,其中 $z$ 为本次操作编号。$n,q\le 10^6$。

题解

先考虑链的做法,用线段树进行区间修改,则要给区间内所有点合并上 $(c,z)$。然而线段树需合并懒标记,会先将后面的操作合并,直接维护可能出错。例如操作依次为 $(x,a),(y,b),(x,c)$ 时,可能在懒标记上先合并后两个得到 $(x,c)$,再跟 $(x,a)$ 合并得到 $(x,a)$,然而结果应为 $(x,c)$。

该错误启发我们对 $(a,b)$ 额外记录一个布尔变量 $f$,表示操作 $b$ 之前是否存在值不为 $a$ 的信息,这样 $t_0=(a_0,b_0,f_0)$ 和 $t_1=(a_1,b_1,f_1)$ 合并时若 $a_0\ne a_1$,答案为 $(a_1,b_1,1)$,否则答案为 $t_{f_1}$。事实上该标记具有结合律,正确性得到保证,可以用懒标记线段树做到 $O(n\log n)$。

再把该做法放到树上,显然可以直接树剖做到 $O(n\log^2 n)$。又因为修改是点到根的路径,直接使用全局平衡二叉树就可以做到 $O(n\log n)$,常数较大,跑不过颜色段均摊 + LCT 或树剖。

D1T2 宝石之国

题意

给定两维大小均为 $n$ 的平面上的 $n$ 个矩形。对于所有 $im\le n$ 的 $i$,求恰好被 $im$ 个矩形包含的面积大小。$\sqrt{n}\le m\le n\le 3\times 10^5$。

题解

考虑对一维扫描线,将矩形加差分为区间加。为方便统计贡献使用分块维护,块内开桶记录个数,每次遍历所有块并枚举所有询问累加答案,时间复杂度为 $O(\frac{n^3}{Bm}+nB+\frac{n^2}B)$。注意到瓶颈在前两项,对其平衡得到 $B=\frac n{\sqrt m}$ 时复杂度为 $O(\frac{n^2}{\sqrt m})$,由 $m$ 范围可得 $m=\sqrt n$ 时取到最大为 $O(n^{\frac 74})$,难以通过。

再考虑记录每个块内的最值,只统计值域区间内的贡献,这样统计某个块的复杂度为 $O(\frac {\max-\min} m)$,因此单轮复杂度只与所有块的极差之和有关。注意到只有散块操作可能使某块的极差增大 $1$,因此所有块的极差之和为 $O(n)$,每轮统计贡献的复杂度为 $O(\frac nm)$。

这样优化后总复杂度为 $O(\frac {n^2}m+\frac {n^2}B+nB)$,对后两项平衡并取到最大,即 $B=m=\sqrt n$ 时,复杂度为 $O(n\sqrt n)$,可以通过。具体实现时由于差分出的加减操作区间相同,可以不用在桶上维护最值,只需记录目前散块操作值的和 $d$,值域即为 $[tag,tag+d]$,这样写常数会小不少。

D2T1 哩哩哩啦哩啦

题意

给定一棵树,要求选择编号在某个区间 $[L,R]$ 内的所有点。有 $m$ 条形如 $(u,k)$ 的限制,表示 $u$ 点的 $k$ 级后代中至少要选择一个点,求合法 $[L,R]$ 中 $R-L$ 最小的。$n,m\le 2\times 10^5$。

题解

$u$ 点的 $k$ 级后代 $x$ 满足 $de_x=de_u+k$ 且 $id_x\in [id_u,id_u+siz_u)$,因此若把所有点以 $de$ 为第一关键字,$id$ 为第二关键字排序,则限制转化为某区间 $[l,r]$ 内至少选一个点,事实上这是一种 BFS 序。注意到所有 $[id_u,id_u+siz_u)$ 两两之间一定不交或包含,因此只找出内部没有其他限制的区间,这些区间一定两两不交。

之后把这些限制区间内的编号拿出来分别排序,然后枚举最终的 $L$,用指针维护每个区间内最小的合法 $x$,取这些编号的最大值为最优的 $R$,扫一遍即可得到答案。由于区间两两不交,这里复杂度为 $O(n)$。总时间复杂度为 $O(n\log n)$,来自排序和二分。

D3T2 还原论

题意

维护序列 $a$,需要支持区间变为异或差分,单点查询,最后输出整个序列。$n\le 2.5\times 10^5,q\le 10^5,a_i<2^{30}$。

题解

先考虑 D 性质,即 $l=1,r=n$ 的情况。此时若进行了 $x$ 次操作,则目前 $a'i=\bigoplus{j\subseteq x}a_{i-j}$,其中 $j\subseteq x$ 表示二进制下 $j$ 为 $x$ 的子集。证明可考虑 $x$ 行的网格图,其所有格中均存在左上到右下的对角线,要求只能向下或右下走。则 $a_{i-j}$ 对 $a'i$ 的贡献次数即为 $(0,i-j)$ 到 $(x,i)$ 的路径条数 ${x}\choose{j}$,根据卢卡斯定理可得当且仅当 $j\subseteq x$ 时有 ${x\choose j}\equiv 1\pmod 2$,$a{i-j}$ 对最终 $a'_i$ 有贡献。

然而 $x$ 较大时无法直接枚举子集,考虑定期重构,每当 $x=B=2^k$ 时更新整个序列并将 $x$ 清空。注意到此时子集只有 $0$ 和 $2^k$,可以 $O(n)$ 更新,复杂度为 $O(\frac{nq}B)$。这样查询时 $x$ 不会超过 $2^k$,直接枚举子集即可,复杂度为 $O(qB)$。取 $\sqrt n$ 附近的 $2^k$ 作为 $B$,得到总复杂度为 $O(q\sqrt n)$。

变为区间修改时,仍对每 $B$ 个修改分一块,回答其内部的询问,同时更新出整个序列在这 $B$ 次修改后的值。注意到由于修改次数不超过 $B$,此时 $a'_i$ 的值只受 $[i-B,i]$ 内 $a$ 值的影响。因此我们再对序列每 $B$ 个元素分一块,则某块内元素的值只受该块和前一个块影响。因此可以先枚举操作块,再枚举序列中每个块依次处理,此时只需要考虑序列中的两个块。

具体地,处理块 $i$ 时拿出块 $i,i-1$,若修改完全包含两个块则只累加 $x$ 标记;若修改只包含两块的一部分,则要清空 $x$ 标记并重构两个块,再进行区间暴力修改。对于某个在块 $i$ 内的询问,可将标记清空再查单点值,或直接枚举 $x$ 的子集求答案。这里清空标记不能暴力枚举所有 $x$ 的子集,而是要进行类似高维前缀和的操作,即枚举每个 $x$ 是 $1$ 的二进制位 $2^k$,并倒序更新所有 $a_i\leftarrow a_{i}\oplus a_{i-2^k}$,容易发现这样操作的结果与暴力枚举子集相同,复杂度 $O(B\log B)$。

现在计算复杂度。有 $O(\frac nB)$ 个序列块,区间修改影响至多四个块,处理时标记清空复杂度 $O(qB\log B)$,暴力更新复杂度 $O(qB)$。每次查询时若清空标记有 $O(qB\log B)$ 的复杂度,若暴力枚举子集有 $O(qB)$ 的复杂度。另外有 $O(\frac qB)$ 个操作块,每个操作块处理完后需下放所有序列块的标记,复杂度 $O(\frac{nq}{B^2}B\log B)=O(\frac {nq\log B}B)$。综上所述总复杂度为 $O(qB\log B+\frac{nq\log B}B)$,取 $B=\sqrt n$ 可得 $O(q\sqrt n\log n)$。这里给出了特殊性质和两种答案统计方式的代码,其中枚举子集的常数较小。

原题

P10009

D3T3 无论

题意

给定长为 $n$ 的数组 $a,b$,可对 $a$ 数组操作,每次可选一段区间 $[l,r]$,将其中所有非零元素均加一或均减一,求将 $a$ 变为 $b$ 的最少操作次数。多测,$n\le 10^6,\sum n\le 3\times 10^6,a_i,b_i\le 10^9$,其中 $30\%$ 满足 $T\le 10,n\le 3000,a_i,b_i\le 500$。

题解(30 分)

首先可以把 $b_i=0$ 的连续段缩成一个点,其 $a_i$ 值为原区间 $a_i$ 的最大值,容易证明这是等价的,因为减到 $0$ 后多减几次不会有影响。以下均认为 $b$ 中不存在连续的 $0$。

注意到在令每个点的减操作在加操作之前时一定能取到最优解。证明考虑先加后减一定能复原,因此对于某种操作序列,若存在 $[l_1,r_1]$ 加在 $[l_2,r_2]$ 减之前且这两个区间有交,不妨设 $l_1\le l_2\le r_1\le r_2$,则可将 $[l_2,r_1]$ 内的两次操作抵消,变为 $[l_1,l_2-1]$ 加和 $[r_1+1,r_2]$ 减,可调整为不劣的合法操作序列。

此时便可以把加减操作分开考虑,以下令 $c_i$ 为减操作次数,$c'i$ 为加操作次数。若操作次数序列为 $x$,则有最小操作次数 $\sum{i=1}^n \max(x_i-x_{i-1},0)$,据此可设计 DP 状态,拆贡献统计答案。注意到若 $b_i\ne 0$,则限制为 $c_i<a_i$,且有 $c'i=b_i-(a_i-c_i)$。然而若 $b_i=0$ 就只有 $c_i\ge a{i}$ 的限制,不好确定 $c'i$。这时 $b{i-1}\ne 0$,可通过 $c_{i-1}$ 确定 $c'{i-1}$,再令 $c'_i=c'{i-1}$ 一定不劣,事实上取在 $[\min(c'{i-1},c'{i+1}),\max(c'{i-1},c'{i+1})]$ 内都是最优的。

因此设 $f_{i,j}$ 表示考虑了前 $i$ 个数且 $c_i=j$ 的最小总贡献。转移时若 $b_{i-1}\ne 0$ 则枚举 $f_{i-1,j}$ 转移,容易计算出操作次数。若 $b_{i-1}=0$ 则有 $b_{i-2}\ne 0$,可枚举 $f_{i-2,j}$,推出 $c_{i-1}=\max (a_{i-1},j))$,再计算 $i-1,i$ 的贡献转移。时间复杂度 $O(TnV^2)$,实现上若只使用合法的 $(i,j)$ 状态转移,常数较小,可以通过 $n\le 3000$ 的数据。

感觉这个 DP 很有思维价值,因此将该部分分记录于此。正解是对该 DP 观察性质并优化到线性,包括凸性和差分数组不超过 $2$ 之类,不是很懂,不管了。

D4T1 象形文字

题意

给出长分别为 $n,m$ 的序列 $a,b$。奇数轮删掉 $a$ 中最大值,偶数轮删掉 $a$ 中最小值,之后拿出 $b$ 中任一元素插入 $a$ 中任意位置,此为一轮操作。求最少多少轮可令 $a$ 序列单增。$n\le 10^5,m\le2\times 10^5$。

题解

设 $p_i$ 表示 $i$ 在 $a$ 中的位置,考虑枚举一段值域区间 $[l,r]$,钦定该区间外的所有数均被删,区间内保留一段子区间。为了最终 $a$ 序列单增,要求 $[l,r]$ 内的 $p$ 数组也单增。由于统计了最终保留其子区间的答案,只需要枚举极长的合法区间即可。

之后记 $ca,cb$ 分别表示 $a$ 中小于 $l$ 和大于 $r$ 的个数,$ta,tb$ 分别表示 $b$ 中小于 $l$ 在 $a$ 中前驱和大于 $r$ 在 $a$ 中后继的个数。该区间是否合法以及最少操作轮数只与这些值有关,之后是一些个人认为意义不大的分讨,此处略去。时间复杂度 $O(n)$。

D5T2 互相抵消

题意

维护序列 $a$,需要支持区间加,区间查询 $\sum_{l'=l}^r\sum_{r'=l'}^r ((\sum_{i=l'}^{r'}a_i)^2+(r-l+2)(r'-l')a_{l'}a_{r'})$,取模。$n,q\le 5\times 10^5$。

题解

考虑把两部分拆开,对 $\sum_{l'=l}^r\sum_{r'=l'}^r (\sum_{i=l'}^{r'}a_i)^2$ 进行转化。注意到后面有 $a_{l'}a_{r'}$ 的乘积形式,因此将平方拆成两个括号中各选一项,再对每一组 $a_ia_j$ 求能贡献到的 $[l',r']$ 个数,可得 A:

$$\sum_{i=l}^r (i-l+1)(r-i+1) a_i^2+\sum_{i=l}^r\sum_{j=i+1}^r2(i-l+1)(r-j+1)a_ia_j$$。

后面部分再进行一些转化,把 $2$ 的系数拆开,得到 B:

$$\sum_{i=l}^r\sum_{j=i+1}^r(i-l+1)(r-j+1)a_ia_j+\sum_{j=l}^r\sum_{i=j+1}^r[(i-l+1)+(j-i)][(r-j+1)+(j-i)]a_ia_j$$。

把后面拆开得到 C:

$$\sum_{j=l}^r\sum_{i=j+1}^r[(i-l+1)(r-j+1)+(r-l+2)]a_ia_j$$。

把 B 前半部分和 C 前半部分结合,得到 D:

$$(\sum_{i=l}^r(i-l+1)a_i)(\sum_{j=l}^r(r-j+1)a_j)-\sum_{i=l}^r(i-l+1)(r-i+1)a_i^2$$。

有 D 后半部分与 A 前半部分抵消,C 后半部分与原式后半部分抵消,得到所求即为 $(\sum_{i=l}^r(i-l+1)a_i)(\sum_{j=l}^r(r-j+1)a_j)$。用数据结构维护 $a_i,ia_i$ 的和即可,时间复杂度 $O(q\log n)$,比较卡常,可能需要用树状数组实现。

D6T1 黄金之心

题意

给出 $V,n,k$,求字符集大小为 $V$,长度为 $n$,且不存在长为 $k$ 的回文子串的字符串数量,取模。$V\le 10^9+7,n\le 1000,k\le 25$。

题解

考虑容斥,即设 $g_x$ 表示有至少 $x$ 个回文子串的字符串数量,则答案为 $\sum_{x=0}^{n-k+1}(-1)^xg_x$。考虑若钦定了某些子串回文,则每个回文子串的每个对应位置均在同一个等价类内,这种钦定方式的方案数即为 $V^c$,其中 $c$ 为等价类个数。这告诉我们 DP 状态不需要记回文串数量或等价类数量,只需要统一放在 DP 值里即可,可以通过带上 $-1$ 或 $V^x$ 转移。

注意到 $k$ 很小,考虑直接设 $f_{i,S}$ 表示考虑了前 $i$ 位,其中最后 $(k-1)$ 位的并查集状态为 $S$ 时带容斥系数的方案数,$S$ 是一个长为 $(k-1)$ 的数组,其中的并查集使用最小表示防止状态数增多。转移是容易的,枚举以 $i$ 结尾的子串是否回文即可,不回文则系数为 $V$,回文则系数为 $-V^{1-c}$,其中 $c$ 为减少的等价类数量。

注意到用等长回文串合并等价类时限制较多,因此合法 $S$ 的数量应该不多,远不到 Bell 数级别。事实上暴搜一下发现 $k=25$ 时只有 $T(25)=90483$ 种,且每种只会转移到其他两种状态,转移数量也是 $O(T(k))$ 的,提前预处理所有转移即可。时间复杂度为 $O(nT(k))$,可以通过。

D6T2 超级电脑

题意

设序列权值为其所有子序列的异或和之和,给定 $n,m,x$,求最小的 $k$ 使得长为 $n$,权值为 $k$ 的序列数量对 $m$ 取模为 $x$,对大质数取模输出。多组测试,$T\le 100,n\le 10^{10^4},x<m\le 10^9$。

题解

考虑序列权值的计算方式,对于每个二进制位,若存在 $1$ 则有 $2^{n-1}$ 种包含奇数个 $1$ 的子序列,否则没有贡献。因此序列权值为 $2^{n-1}V$,其中 $V$ 为所有数的按位或值。所以当 $2^{n-1}\mid k$ 时有 $V=\frac{k}{2^{n-1}}$,方案数为 $(2^n-1)^c$,其中 $c$ 为 $V$ 中 $1$ 的个数;不整除时方案数为 $0$。

反过来由 $x$ 构造 $k$ 时,要求 $(2^n-1)^c\equiv x\pmod m$,使用扩展 BSGS 求出最小的 $c$,答案即为 $(2^c-1)\times 2^{n-1}$。所有 $2^n$ 均需要使用扩展欧拉定理降幂求解,细节此处不表。还有 $n,x,m$ 为 $0,1$ 时的诸多边界情况,此处均略去。总时间复杂度可以做到 $O(T(\sqrt m+\log n))$。

D7T1 Kanade 的水杯

题意

有 $n$ 个水杯,分别有容量 $a_i$,初始第一个满,其余空。对 $i\in[1,n]$ 依次操作,等概率选择一个其他水杯,将第 $i$ 个水杯中的水倒入,直到该杯满或第 $i$ 个杯空。对每个水杯求其最终期望水量。$a_i\le n\le 10^5$。

题解

注意到 $i$ 水杯操作时,其后所有水杯一定为空,因为同时只会存在只多一个有水且未操作的水杯。因此若所选的目标 $j<i$,之后的操作均可忽略。另外 $j<i$ 时转移水量一定为 $\min(a_j,b_i)$,其中 $b_i$ 为目前 $i$ 的水量。当 $j$ 为空时显然,$j$ 不空时 $b_i$ 一定是从 $j$ 中转移来的,因此该式必然取到 $b_i$,该结论成立。

据此可设计 DP 状态,设 $f_{i,x}$ 表示操作到 $i$ 时其水量为 $x$ 的概率,则可以转移给 $j>i$ 的 $f_{j,\min(a_j,x)}$,或是直接给 $j<i$ 的 $j$ 累加上 $f_{i,x}\times\min(a_j,x)$ 的答案,两处都还要乘上 $\frac 1{n-1}$ 作为系数。这样要枚举 $i,x,j$ 三维,复杂度为 $O(n^3)$。

注意到所有转移均与 $i$ 无关,而只与 $i,j$ 的大小关系有关。考虑使用前缀和优化,设 $s_{i,x}=\sum_{j=1}^i f_{i,x}$,则可以枚举 $j,x$ 两维转移,转移式与上面相似,复杂度为 $O(n^2)$。此处为了保证复杂度,需要预处理存在 $x$ 单位水时向外转移的总剩余量 $c_x$,答案还要累加上 $\frac 1{n-1}\sum_{x=1}^n c_xf_{i,x}$。

再次观察转移过程,发现对于 $x>a_i$ 有 $f_{i,x}=0$;对于 $x<a_i$,有 $f_{i,x}=\frac1{n-1}s_{i-1,x},s_{i,x}=s_{i-1,x}+f_{i,x}=\frac n{n-1}f_{i-1,x}$;而 $f_{i,a_i}=\frac 1{n-1}\sum_{y=a_i}^n s_{i-1,y}$,据此也可以更新 $s_{i,a_i}$。注意到此处 $s$ 的变化只有区间乘和单点加,需要支持区间查。统计答案时将 $f$ 也差分成 $s$ 即可,还需要 $c_xs_{i,x}$ 和 $xs_{i,x}$ 的区间和。这些均可使用线段树维护,时间复杂度为大常数 $O(n\log n)$。

D8T1 Eileen 的游戏

题意

给定两个长为 $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)$。

原题

P12558

P10009 题解

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

题意

维护序列 $a$,需要支持区间变为异或差分,单点查询,最后输出整个序列。$n\le 2.5\times 10^5,q\le 10^5,a_i<2^{30}$。

题解

先考虑 D 性质,即 $l=1,r=n$ 的情况。此时若进行了 $x$ 次操作,则目前 $a'i=\bigoplus{j\subseteq x}a_{i-j}$,其中 $j\subseteq x$ 表示二进制下 $j$ 为 $x$ 的子集。证明可考虑 $x$ 行的网格图,其所有格中均存在左上到右下的对角线,要求只能向下或右下走。则 $a_{i-j}$ 对 $a'i$ 的贡献次数即为 $(0,i-j)$ 到 $(x,i)$ 的路径条数 ${x}\choose{j}$,根据卢卡斯定理可得当且仅当 $j\subseteq x$ 时有 ${x\choose j}\equiv 1\pmod 2$,$a{i-j}$ 对最终 $a'_i$ 有贡献。

然而 $x$ 较大时无法直接枚举子集,考虑定期重构,每当 $x=B=2^k$ 时更新整个序列并将 $x$ 清空。注意到此时子集只有 $0$ 和 $2^k$,可以 $O(n)$ 更新,复杂度为 $O(\frac{nq}B)$。这样查询时 $x$ 不会超过 $2^k$,直接枚举子集即可,复杂度为 $O(qB)$。取 $\sqrt n$ 附近的 $2^k$ 作为 $B$,得到总复杂度为 $O(q\sqrt n)$。

变为区间修改时,仍对每 $B$ 个修改分一块,回答其内部的询问,同时更新出整个序列在这 $B$ 次修改后的值。注意到由于修改次数不超过 $B$,此时 $a'_i$ 的值只受 $[i-B,i]$ 内 $a$ 值的影响。因此我们再对序列每 $B$ 个元素分一块,则某块内元素的值只受该块和前一个块影响。因此可以先枚举操作块,再枚举序列中每个块依次处理,此时只需要考虑序列中的两个块。

具体地,处理块 $i$ 时拿出块 $i,i-1$,若修改完全包含两个块则只累加 $x$ 标记;若修改只包含两块的一部分,则要清空 $x$ 标记并重构两个块,再进行区间暴力修改。对于某个在块 $i$ 内的询问,可将标记清空再查单点值,或直接枚举 $x$ 的子集求答案。这里清空标记不能暴力枚举所有 $x$ 的子集,而是要进行类似高维前缀和的操作,即枚举每个 $x$ 是 $1$ 的二进制位 $2^k$,并倒序更新所有 $a_i\leftarrow a_{i}\oplus a_{i-2^k}$,容易发现这样操作的结果与暴力枚举子集相同,复杂度 $O(B\log B)$。

现在计算复杂度。有 $O(\frac nB)$ 个序列块,区间修改影响至多四个块,处理时标记清空复杂度 $O(qB\log B)$,暴力更新复杂度 $O(qB)$。每次查询时若清空标记有 $O(qB\log B)$ 的复杂度,若暴力枚举子集有 $O(qB)$ 的复杂度。另外有 $O(\frac qB)$ 个操作块,每个操作块处理完后需下放所有序列块的标记,复杂度 $O(\frac{nq}{B^2}B\log B)=O(\frac {nq\log B}B)$。综上所述总复杂度为 $O(qB\log B+\frac{nq\log B}B)$,取 $B=\sqrt n$ 可得 $O(q\sqrt n\log n)$。这里给出了特殊性质和两种答案统计方式的代码,其中枚举子集的常数较小。

共 137 篇博客