做题记录 2
上一个写的太多了,卡爆了。所以再开一个。
P4321 随机漫游
一道综合多种算法的好题。
首先按照图上随机游走的套路,再依据 很小的限制,可以设出 方程:设 表示当前走过的点集为二进制数 ,当前在 点,再走完所有点的期望步数。那么显然有 。
然后写一下转移柿子:
然后发现这是一个 元的线性方程组。所以可以直接高斯消元。时间复杂度 。但是显然爆了。
再考虑将转移方程改写一下,分 原本是否属于 进行讨论:
整理得到:
这样,只需要按照集合 大小倒序枚举,方程组大小自然降为 。
时间复杂度 。
P3723 [AH2017/HNOI2017] 礼物
首先发现加减相对于两个手环是对称的。因此可以把对一个手环的减法转化成对另一个手环的加法。这样可以假设全是在第一个手环上执行的加减操作。
第一个手环执行了加 的操作,且旋转过之后的序列为 ,第二个手环为 。计算差异值并化简,可以得到差异值是:
可以发现,这个序列只有最后一项是不定的。
因此将 序列翻转后再复制一倍,与 卷积,答案就是卷积后序列的 项系数的 。
直接暴力枚举 ,加上前面依托就行了。
P3514 [POI2011] LIZ-Lollipop
回归简单题。
给定权值为 或 的序列,每次询问有没有权值等于 的子区间。
神仙思维题。
假设当前有一个序列权值和为 。那么分下面情况讨论:
-
, 的权值和为 。
-
, 的权值和为 。
-
, 的权值和为 。
综上,总能根据一个权值为 的序列,构造出权值为 的序列。
因此只需要知道序列中,权值为奇数的最大子区间和权值为偶数的最大子区间就可以了。
代码下周再补。
P8060 [POI2003] Sums
同余最短路典题。
CF1527E Partition Game
首先能够想到一个很典的 dp:记 表示前 个元素划分成 段的最小代价。转移 ,时间 。
考虑优化。首先看这个转移柿子:,这个东西看起来就很凸性。看了看题解确实也是这样的,但是我不会证明。
接下来考虑线段树优化。首先开一个线段树,把 和 值加起来放到线段树里。考虑每次转移都是加入一个新元素,并且对前面的 值没有影响。接下来考虑这个新加入的元素对前面 值的影响。可以发现,他只对 的有影响。
所以只需要线段树支持区间加,区间取 ,单点插入就可以了。
CF1149C Tree Generator™
可以发现,两个点之间的距离,就是这两个点之间括号序列,消掉匹配的括号以后,剩下的没有匹配的括号。
因此问题转化为求最大权值子段,子段权值为消掉合法括号匹配之后的括号数。
这个东西可以线段树维护一下。由于最后括号序列一定形如 ,可以记一下当前区间剩下的 的数量分别是多少,以及区间最大权子段。转移的时候分类讨论一下即可。
CF242E XOR on Segment
这道题有许多做法,其中最简单的就是拆位建 棵线段树爆算。
不赘述了。依据的是亦或的位独立性。。
P4046 快递服务
不妨设 表示当前三个司机在 号公司,而且已经遍历到了 号公司的 minimum cost。
转移是平凡的。可以做到 ,。由于常数小 1s 完全不虚。
signed main() {
read(n);
rep(i, 1, n) rep(j, 1, n) read(d[i][j]);
a[ ++ m] = 3, a[ ++ m] = 2, a[ ++ m] = 1;
while (scanf("%lld", &a[ ++ m]) != EOF);
memset(f, 0x3f, sizeof f); f[1][2][1] = 0;
rep(i, 3, m) {
rep(j, 2, i) rep(k, 1, j) f[(i & 1) ^ 1][j][k] = INF;
rop(j, 2, i) rop(k, 1, j) {
chkmin(f[(i & 1) ^ 1][j][k], f[i & 1][j][k] + d[a[i]][a[i + 1]]);
chkmin(f[(i & 1) ^ 1][i][k], f[i & 1][j][k] + d[a[j]][a[i + 1]]);
chkmin(f[(i & 1) ^ 1][i][j], f[i & 1][j][k] + d[a[k]][a[i + 1]]);
}
} rep(i, 1, m) rep(j, 1, m) ans = min(ans, f[m & 1][i][j]);
printf("%lld\n", ans); return 0;
}
P4158 粉刷匠
发现木板的粉刷相对独立。若求出每个木板粉刷 次获得最大收益 ,则容易进行分组背包。
现在考虑如何求 。不妨设 表示粉刷了前 个格子,粉刷了 次获得的最大收益。枚举上一次粉刷的位置,可以得到转移
好像应该是 。不管了,大概就这样。最后背包合并就行了。。
void calc(int n) {
rep(i, 0, m) rep(j, 0, t) f[i][j] = 0;
rep(i, 1, m) s1[i] = s1[i - 1] + (g[n][i] == '1');
rep(i, 1, m) s0[i] = s0[i - 1] + (g[n][i] == '0');
rep(i, 1, m) rep(j, 1, t) rop(k, 0, i) {
f[i][j] = max(f[i][j], f[k][j - 1] + s1[i] - s1[k]);
f[i][j] = max(f[i][j], f[k][j - 1] + s0[i] - s0[k]);
} rep(i, 0, t) rep(j, 0, m) w[n][i] = max(w[n][i], f[j][i]);
}
signed main() {
read(n, m, t);
rep(i, 1, n) scanf("%s", g[i] + 1);
rep(i, 1, n) calc(i); memset(f, 0, sizeof f);
rep(i, 1, n) rep(j, 0, t) rep(k, 0, j)
f[i][j] = max(f[i][j], f[i - 1][j - k] + w[i][k]);
rep(i, 0, t) ans = max(ans, f[n][i]); printf("%lld\n", ans);
}
不妨让我们一起来考虑优化!可以发现,背包合并的物体体积是 而不是 级别的,因为最多染 次。
复杂度瓶颈变成了预处理。不妨改变一下状态,设 表示染了前 个格子,用了 次,最后一个染的是红 / 蓝。这样就可以做到 转移。故做到 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示