2023NOIP A层联测10 (ACCODER 411)

2023NOIP A层联测10 (ACCODER 411)

2023年10月12日 / 比赛 / 信息学

代码与题面

商品打包

如果直接做需要 O ( n 2 ) O(n^2) O(n2),思考能否从上一种情况推出下一种。

如果 i i i 1 1 1~ n n n,那么每次要删掉 a [ i ] a[i] a[i],这不太好操作。我们考虑倒序操作,那么我们每次只需要加入 a [ i ] a[i] a[i]即可。虽然我们加入的顺序反了,但这并不影响最终结果。

为了严谨我们尝试证明。考虑反证法,若翻转后做可以减少背包数,那么翻转之前的第一个背包(也就是翻转之后的最后一个背包)翻转后包含的物品数必定大于翻转前。然而物品序列没有改变,这样就与题目的装包策略矛盾。

集合

采用记忆化搜索,时间复杂度为 O ( a m ) O(am) O(am)其中 a a a为最大答案。初步估计 a a a可能在 ∏ i = 1 10 log ⁡ p [ i ] m \prod_{i=1}^{10} \log_{p[i]} m i=110logp[i]m p p p为质数列表)左右, m m m最大为 99991 99991 99991

实践出真知,发现答案并不大,解决这题。值得注意的是,我们必须要进行一个排序,不然记忆化会导致WA,你可以尝试集合为 4 , 2 4,2 4,2的情况。

最小生成树

首先,这个图非常稠密,朴素的Kruskal算法需要 O ( n 2 log ⁡ n 2 ) O(n^2 \log n^2) O(n2logn2),不太优秀,并且不好优化。

基于Prime

首先我们打一个 O ( n 2 ) O(n^2) O(n2)的朴素Prime,分析算法流程,我们每将一个新的节点加入连通块,都要将到 n n n个数刷新,并且非常有规律可循,考虑使用线段树维护。

考虑固定 i i i j j j为新加入的节点,因为边权为 a [ j ] − a [ i ]   ( i < j ) a[j]-a[i] \ (ia[j]a[i] (i<j) a [ i ] − a [ j ]   ( j < i ) a[i]-a[j] \ (ja[i]a[j] (j<i),其中 a [ i ] a[i] a[i]为定值,那么我们需要两棵线段树分别维护区间修改 a [ j ] a[j] a[j]

同时,更新过的节点不能再更新,所以我们还要支持修改 a [ i ] a[i] a[i]为极大值,使得不可能再选择其更新。对于查询,我们只需要查询 1 1 1~ n n n的区间答案就行了。

具体的,我们用两棵线段树 T 1 , T 2 T_1,T_2 T1,T2,变量名定义如下。

变量名 类型 含义
b int 更新点的a最小值
lzb int 懒标记
l int 左端点
r int 右端点
a pii 原来的a最小值及位置
mn pii 最小的边权及位置

pii就是pair

值得注意的是合并的时候千万不能合并 b b b,因为子区间的 b b b并不能覆盖父区间。记得开long long

对于较慢的评测机,可能需要卡常(注释掉的都是卡常牺牲品)。

基于Borůvka

待学习,求教。

子序列

注意,为了方便,字符串从 1 1 1开始记录。

我们考虑动态规划,先预处理 p r e [ i ] [ j ] pre[i][j] pre[i][j] n x t [ i ] [ j ] nxt[i][j] nxt[i][j]分别表示在第 i i i位时字符 j j j的前驱与后继,如果没有,则为 0 0 0

预处理 f [ i ] [ j ] f[i][j] f[i][j]表示,从 n n n i i i,每个 s [ i ] s[i] s[i]隔开的段之间含有 j j j字符的最长字符数。容易得到转移方程:

{ f [ i ] [ j ] = f [ n x t [ n x t [ i ] [ j ] ] [ s [ i ] ] ] [ j ] + 2   ( n x t [ i ] [ j ] ≠ 0 ) f [ i ] [ j ] = 1   ( n x t [ i ] [ j ] = 0 ) \begin{cases} & f[i][j]=f[nxt[nxt[i][j]][s[i]]][j]+2 \ (nxt[i][j] \neq 0) \\ & f[i][j]=1 \ (nxt[i][j]=0) \end{cases} {f[i][j]=f[nxt[nxt[i][j]][s[i]]][j]+2 (nxt[i][j]=0)f[i][j]=1 (nxt[i][j]=0)

对于每一个查询,我们直接枚举字符 i i i j j j,该情况下的答案 t m p tmp tmp为。

{ t m p = 0   ( n x t [ l ] [ i ] > r ) t m p = f [ n x t [ l ] [ i ] ] [ j ] − f [ p r e [ r ] [ i ] ] [ j ] + 1   ( p r e [ r ] [ i ] > p r e [ r ] [ j ] ) t m p = f [ n x t [ l ] [ i ] ] [ j ] − f [ n x t [ r ] [ i ] ] [ j ]   ( p r e [ r ] [ i ] < = p r e [ r ] [ j ] ) \begin{cases} & tmp=0 \ (nxt[l][i]>r) \\ & tmp=f[nxt[l][i]][j]-f[pre[r][i]][j]+1 \ (pre[r][i]>pre[r][j]) \\ & tmp=f[nxt[l][i]][j]-f[nxt[r][i]][j] \ (pre[r][i]<=pre[r][j]) \end{cases} tmp=0 (nxt[l][i]>r)tmp=f[nxt[l][i]][j]f[pre[r][i]][j]+1 (pre[r][i]>pre[r][j])tmp=f[nxt[l][i]][j]f[nxt[r][i]][j] (pre[r][i]<=pre[r][j])

统计最优答案即可。

你可能感兴趣的:(信息学,比赛,算法,c++)