思路讲解
1 | // 以i为起点,初始值为w,所能够获得的最大收益 |
这道题目,我认为关键点在这里,因此我们推一下
不难发现,无论怎么样操作,一个星球的收益一定是一个连乘的式子,因此上述操作就不难理解了。
AC代码
https://vjudge.net/solution/62959677
1 | // by Gospel_rock |
1 | // 以i为起点,初始值为w,所能够获得的最大收益 |
这道题目,我认为关键点在这里,因此我们推一下
W×val+W×(1−0.01×cost)×val2+W×(1−0.01×cost)2×val3
不难发现,无论怎么样操作,一个星球的收益一定是一个连乘的式子,因此上述操作就不难理解了。
https://vjudge.net/solution/62959677
1 | // by Gospel_rock |
(A[1]+⋯+A[len])modM=0
(A[2]+⋯+A[len+1])modM=0
(−A[1]+A[len+1])modM=0
Sumi+L≡Sumi(modM)(∀i=0,…,N−L).
https://chatgpt.com/c/68a1e9d2-d4f4-832a-bc89-13ae40f158c5
br 是指的差值的模(模M)。具体来讲,就是 (−A[1]+A[len+1])modM=0 ,(−A[0]+A[len])modM=0 这种位置很多,他们成周期性出现,即是:
b1=A[1]modM=A[len+1]modM=A[2len+1]modM⋯
那么,不难发现,除了要满足传递性,还要满足初始条件,即:
b1+b2+⋯+blen≡0(modM)
然后可以定义一个dp数组,dp[i][j] 表示已经选了前 i 个数字,且 sum≡j(modM) 所需的代价为几(sum=b1+b2+⋯+bi)?
为了快速计算这个dp,可以使用一个辅助数组g[i][j] 是指b[i] 到达b[i]≡j(modM) 所需要的总代价。朴素计算需要O(LMLN)⇒O(MN) ( 好像还可以?)
https://atcoder.jp/contests/abc419/submissions/68614283
1 | // by Gospel_rock |
使得数组趋同,所需要的最少区间加一操作数量。
题目描述
给定 n 个学生的初始好感度序列 a1,a2,…,an。
每天可以且必须进行一次操作:选择一个区间 [l,r] (1≤l≤r≤n),将该区间内所有学生的好感度加 1(即对于所有 l≤i≤r,执行 ai:=ai+1)。
求使得最终序列中最多出现 m 种不同数值所需的最小操作次数(最小天数)。
输入描述
第一行包含一个整数 T (1≤T≤10),表示测试数据组数。
对于每组测试数据:
第一行包含两个整数 n,m (1≤n≤400,1≤m≤2),分别表示学生数量和允许的最大不同数值种数。
第二行包含 n 个整数 a1,a2,…,an (0≤ai≤100),表示初始好感度。
输出描述
对于每组测试数据,输出一行一个非负整数,表示所需的最小操作次数。
样例
1 | 输入 |
样例解释
第一组数据 (n=3,m=1):
初始序列为 [3, 1, 3],目标是让所有数字相同(最多 1 种数值)。
选择区间 [2,2] 进行操作,序列变为 [3, 2, 3]。
再次选择区间 [2,2] 进行操作,序列变为 [3, 3, 3]。
共需 2 次操作,序列中只有数值 3,满足条件。
第三组数据 (n=5,m=2):
初始序列为 [5, 1, 6, 1, 8],目标是让序列中最多只有 2 种不同的数值。
最小需要 3 次操作。
首先我们注意到一件事情,就是这个 M 等于一或者 M 等于二。说白了要么变成同一个数,要么变成两个数。
我是这么感觉的,修改一个数,就是把所有的值修改为最大值。修改两个数其实也简单。修改两个数就是一个最大值,一个次大值,然后把其他的值都修改为次大值就好了。
上面就是我的感觉啊,我们先尝试一下,看看对不对。先尝试手磨一下样例。
不,手磨样例以后,我们发现把所有值修改为最大值,在只修改一个数的时候应该是对的。但是修改两个数的时候,这个情况就比较复杂了。修改两个数的话,我们之前的想法应该是错的。只有一个是对的,就是应该就是先要把这些数,其中的一些数肯定是要变为最大值的,其中的一些数肯定是要变为最大值的。但是至于另外一个值需要怎样取,就比较麻烦了。
这是整道题的基础。假设目标数组是 b(满足 bi≥ai),从 a 变到 b 的最少操作次数是多少?
令 di=bi−ai≥0(每个位置需要增加的量)。最少操作数 = 区间覆盖次数,等于:
d1+i=2∑nmax(0, di−di−1)
大的目标值一定是 v=M=max(a)(因为原数组最大值的那个位置只能往上走,强制拉高这一组的目标,v<M 不可能,v>M 只会更贵)。
小的目标值 u:枚举 u 从 0 到 M−1。对于每个固定的 u:
对于固定的 u,定义:
dp[i][g]=处理前 i 个位置,第 i 个位置属于第 g 组时的最小操作数
你可以用 u=3、样例 3 手跑一遍 DP 验证答案是 3,感受一下正确性。然后就可以动手实现了。
OK 啊,偷偷看了一眼题解,这个题解写的还是可以的。比这垃圾 AI 提示写的好。这 AI 提示,我告诉他我的思路,我干脆比不告诉他我的思路还好,写的还好一点。这真的纯纯傻逼,还不如不写。
M 等于一的情况,一种比较方便的实现方法呢,就是直接选择一个极长段,这个极长段中的所有数都比最大值小。不断地选择这样的极长段进行操作,记录一下找不到这个这样子的极长段所需要的操作数量。说白了,这个做法就是一个贪心。
现在问题在于 M 等于2的情况下,另外一个值怎样取?但是你会发现,其实这道题目它的值域非常小啊,另外一个值怎样取?你不知道怎样取,你直接枚举就行了,一共就100个值,它总归是变成比最大值小的值,是吧?
OK 啊,我已经想到了一种可以解决 M 等于2的情况下的 DP 的方法。

不过这个方法目前的瓶颈在于,就是说从转移过来的位置到我的这个 pos 之间,这一段的求解,如果使用贪心法有点慢了。
我们现在的问题如下:
对于段 [l,r],把它所有元素变成 max(a[l..r]) 所需的最小操作数,如何快速预处理?
(对于任意目标值 T=max(a[l..r])+k,代价只比 T=max 时多 k,而目标值 T 又不可能比 Max A 从 L 到 R 还小,这是不可能的。)
操作是"选一个连续区间,全体 +1"。目标是把 a 变成 b(bi≥ai)。
令 di=bi−ai,即每个位置还需要增加的量。问题变成:用最少次"选连续区间全体 -1"操作,把 d 清零。
从左到右看 d 数组:
操作数=dl+i=l+1∑rmax(0, di−di−1)
令目标 bi=mx=max(a[l..r]),则 di=mx−ai。
看差值:
di−di−1=(mx−ai)−(mx−ai−1)=ai−1−ai
mx 抵消了。所以:
max(0, di−di−1)=max(0, ai−1−ai)
这个东西跟 mx 无关,只跟原数组相邻元素有关**。(这也是后续我们可以 O1 求的这个原因啊。)**
代回去:
cost(l,r)=第一项(mx−al)+∑i=l+1rmax(0, ai−1−ai)
定义:
P[i]=j=2∑imax(0, aj−1−aj)
则 ∑i=l+1rmax(0,ai−1−ai)=P[r]−P[l]。
最终:
cost(l,r)=(mx[l][r]−al)+P[r]−P[l]
这就是完整的推导过程。
</div>
如果说我们画一张图具体来表达的话,就如下图:

哎,上面的思路都被op4.6带歪了。我们应该让他先写一下这个程序,然后看看AC的以后,再写完这个顺序,发现他这个思路根本完全就是错的,提交上去以后,忘了以后,我仔细想一下,他这个思路完全是错的。嗯,当然也没有说错的那么明显,但是段间的这个逻辑不是很清楚,段间的这个逻辑是实际上是有问题的,段内的逻辑它的这个求解的逻辑是非常正确的,但是段间的这个逻辑有问题。
还有这个错误解法,还有一个问题就是反例,在M=二的情况下,最就是这两个值不一定就是一个最大值,就是这两个值中不一定包含最大值,即最优解当中相同的这两个数不一定包含最大值。
你这个判断直觉很强,但结论确实不成立。
我不跟你抬杠,直接给你一个最小反例:
[0, 3, 0, 1]m = 2mx = 33,最优至少是 2 天。[1,3,1,1](两值 {1,3}):d=[1,0,1,0]= d1 + Σmax(0,di-di-1) = 1+0+1+0 = 23,取两值 {1,4},变成 [1,4,1,1]:d=[1,1,1,0]= 1+0+0+0 = 1mx 必须是最终两值之一”这个约束会 WA。如果你仍然坚持“固定 mx 来写”,我可以按这个约束给你写一个版本,但我会明确标注:这是受限解法,不是题目的全局最优解。
其实说白了这个判断,细想一下就是不对的,虽然最大值增加没有太大意义,但是如果说在有两个数的情况下,我去跨越它,去进行一些增加,也是有可能的。
可以,我把这版 DP 的核心讲清楚,尽量不绕。
你原来那版本质上是“分段 + 两个目标值”。问题不在“分段”,而在两个隐含假设:
mx(全局最大初值)是错的。{3,7} 这类,不一定包含 mx。max(dp, cost) 那个就是典型错位)。假设最后只保留两个值:low <= high。
每个位置 i 只能选其中一个目标,且必须满足 a[i] <= target(只能加不能减)。
定义:
i 选了目标 t_i,则该位置需要增量 d_i = t_i - a_i >= 0。d 造出来后,最少操作数是经典式子:cost=d1+i=2∑nmax(0, di−di−1)
设 f[i][g]:
i 位;i 位选的是第 g 个目标(g=0 表示 low,g=1 表示 high);tar(g) = (g==0 ? low : high)d(i,g) = tar(g) - a[i]i=1):a[1] <= low,f[1][0] = low - a[1]a[1] <= high,f[1][1] = high - a[1]i>=2):pg 转到 g:f[i][g]=min(f[i][g], f[i−1][pg]+max(0, d(i,g)−d(i−1,pg)))
最终固定 (low,high) 的答案是:
min(f[n][0],f[n][1])
a_i <= 100,值域小,所以直接枚举 low, high 就行。O(V^2 * n * 4),V 在 100 量级,n<=400,完全够。如果你愿意,我下一条可以专门按你现在这份代码变量名,给你写“逐行对应解释”(哪一行是 d_1,哪一行是 max(0, d_i-d_{i-1})),这样你对照起来会最快。
那么,他写的还是挺好的。嗯,思路其实很简单,就是在已知upper和已知lower的情况下,那么这个实际上可以使用一个 O(n) 的DP就可以去解决这个问题。因为其实一个位置,他对答案的贡献只取决于他前面一个位置和它自己的这个位置,它取什么值。
这个下面就是已经知道了upper和lower以后,怎么样去DP的这个过程的代码。嗯,然后加粗高亮的地方呢,是有点问题。但是当时挖的地方,当时upper写成了max,然后这个DPI1呢,写成了DPI0。
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=82501084
我感觉想规避DPI1的错误,我们在这里取命只是为了让他不要比infinite高。那么我们直接命里面放一个INF就行了,不要写真实的东西,参有的时候会造成问题,不要写真实的东西,就写一个常数进去,就是能用常数的地方就用常数。
1 | vector<array<ll,2>> diff_arrays(N+2); |
AC
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=82503145
1 | /** |
1 | /** |
1 | /** |
回顾代价公式:
cost=d1+i=2∑nmax(0, di−di−1)
对于固定的小目标值 u(外层枚举),令:
dp[i][g]=处理完前 i 个位置、第 i 个位置属于第 g 组时的最小总操作数
转移(每步 O(1),无需关心段的内部):
dp[i][g]=g′∈{0,1}min(dp[i−1][g′]+max(0, di(g)−di−1(g′)))
| 层次 | 复杂度 |
|---|---|
| 枚举 u(0 到 M≤100) | O(M) |
| 每个 u 跑一遍 DP | O(n) |
| 总计 | O(M⋅n)≈O(100×400) |
| 远远够用,不需要任何段内贪心。 |
你之前思路里的"段"其实并不是必要的抽象——相邻两位之间的 max(0,di−di−1) 本身就已经捕捉了所有段的边界信息,DP 直接逐位推进即可。
dp[pos][g] = 前 pos 个位置处理完毕、最后一段(以 pos 结尾的连续段)属于第 g 组时的最小操作数。prev(0 到 pos-1)来,段 [prev+1, pos] 全部是第 g 组。对于段 [prev+1, pos] 全在 g 组(目标值 tg 为 u 或 M),它对总操作数的贡献分两部分:
① 边界项(连接前一段和本段,O(1)):
max(0, tg−aprev+1−(tg′−aprev))
② 段内部项:
i=prev+2∑posmax(0, di(g)−di−1(g))=i=prev+2∑posmax(0, ai−1−ai)
关键:这个内部项与 tg(即 u 还是 M)完全无关! 可以预处理前缀和:
P[i]=j=2∑imax(0, aj−1−aj)
dp[pos][g]=prev∈[0,pos−1]g′∈{0,1}min( dp[prev][g′]+max(0, tg−aprev+1−tg′+aprev)边界项,O(1)+P[pos]−P[prev+1]内部项,O(1) )
prev=0 时边界项 = tg−a1(无前一段,d0=0)。一句话总结:预处理前缀和 P[i],段内部项变 O(1) 查询,转移总体 O(n²),搞定。
这两个 AI 回答都写的比较招笑,我们再看一看它有没有更好的回答。
预处理前缀和,令:
P[i]=j=2∑imax(0, a[j−1]−a[j])
(O(n) 预处理,O(1) 查询)
预处理区间最大值:
mx[l][r]=max(a[l],…,a[r])
cost(l,r)=(mx[l][r]−a[l])+P[r]−P[l]
推导:令 di=mx[l][r]−a[i],代入操作数公式:
dl+i=l+1∑rmax(0,di−di−1)=(mx−a[l])+i=l+1∑rmax(0, a[i−1]−a[i])=(mx−a[l])+P[r]−P[l]
目标值变为 mx[l][r]+k,代价恰好增加 k(因为 dl 增加 k,内部差值不变):
cost(l,r,target=mx+k)=cost(l,r)+k
a=[5,1,6,1,8],P=[0,4,4,9,9],整段 [1,5]:mx=8,cost=(8−5)+9−0=12 ✓

思路不能说是一模一样吧,只能说是非常相似。
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=78887151
1 | // by Gospel_rock |
不难发现,合法字符串必须包含 () 字符。
于是套用manacher就行,注意特判radius=1的奇数长度回文串
1 | FOR(i,0,SZ(res)-1){ |
https://acm.hdu.edu.cn/contest/view-code?cid=1180&rid=12078
1 | // by Gospel_rock |
