Let bygones be bygones

news/发布时间2024/5/17 17:46:34

Let bygones be bygones.

Oh, I have.

欢乐 dp 场。总之我们通过神秘方法,一个像样的正解都没有写,获得了三位数的好成绩。

六出祁山

一个有脑子就会写的暴力 dp,定义 \(f_{i, j}\) 表示处理到第 \(i\) 个,高度改为 \(j\)。有 \(f_{i, j} = f_{i - 1, k} + | h_i - j| (|k - j| \leq d)\)。然后这样是 \(O(n d^ 2)\) 的,考虑优化。那么显然只能优化这个状态数,其它的目前还优化不了。然后就有一个非常离谱的优化,感性理解一下,相邻差都不大于 \(d\),还在 \(h\) 元素的基础上修改,那么是不是最优状态可以是 \(h_i + kd, k \in \mathbb{Z}\) 呢?

然后状态数从 \(d\) 变到了 \(n ^ 2\)。时间复杂度 \(O(n ^ 5)\)。重新看原来的 dp 柿子,\(j\) 固定,\(k\) 显然也固定,那么 \(j\) 每次循环都增加,只需要用滑动窗口维护 \(k\) 就好了。时间复杂度 \(O(n ^ 3)\)。甚至可以 set。

namespace liuzimingc {
const int N = 305, M = 9e4 + 5, INF = 1e9;
#define endl '\n'
#define int long longint n, d, h[N], v, a[N], ans, q[M];
int f[N][M];
vector<int> lsh;int get(int x) {return lower_bound(lsh.begin(), lsh.end(), x) - lsh.begin();
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr); cout.tie(nullptr);cin >> n >> d;for (int i = 1; i <= n; i++) cin >> h[i], v = max(v, h[i]);if (abs(h[1] - h[n]) > (n - 1) * d) return cout << -1 << endl, 0;for (int i = 1; i <= n; i++)for (int j = -n; j <= n; j++) {int x = h[i] + j * d;if (x >= 0 && x <= v) lsh.push_back(x);}sort(lsh.begin(), lsh.end());lsh.resize(unique(lsh.begin(), lsh.end()) - lsh.begin());memset(f, 0x3f, sizeof(f));f[1][get(h[1])] = 0;for (int i = 2; i <= n; i++) {int head = 1, tail = 0, r = 0;for (int j = 0; j < lsh.size(); j++) {while (head <= tail && lsh[q[head]] < lsh[j] - d) head++;while (r < lsh.size() && lsh[r] <= lsh[j] + d) {while (head <= tail && f[i - 1][q[tail]] > f[i - 1][r]) tail--;q[++tail] = r++;}f[i][j] = f[i - 1][q[head]] + abs(lsh[j] - h[i]);}}cout << f[n][get(h[n])] << endl;return 0;
}
#undef int
} // namespace liuzimingc

水淹七军

糊里糊涂,总之用了一个完全不知道的 Mirsky(Dilworth)定理:\(S\) 的最长链长度等于最小的反链覆盖数。

然后转换成这个,然后就开始分层 dp 了。是的我是 C 的,现在都没懂,我骄傲😊(假的其实半懂半不懂)

煮酒论英雄

直接看题解就好了。写的挺清楚。你甚至不需要 KMP,可以直接 Hash 暴力。想到“将存在包含关系的字符串处理掉”还是挺重要的???

namespace liuzimingc {
#define endl '\n'
#define ull unsigned long long
const int N = 20, M = 2e4 + 5, P = 13331, INF = 1e18;int n, len[N], a[N], tot, mx[N][N][2][2], f[1 << 16][N][2], sum, ans; // not hard to "design"!
pair<int, int> broke_my_promise[N];
char s[N][M];
ull p[M], hash[N][M][2];
bool vis[N];ull get(int i, int l, int r, int typ) {return hash[i][r][typ] - hash[i][l - 1][typ] * p[r - l + 1];
}bool check(int x, int y) { // check if s[y] is a subcheese of s[x]if (len[y] > len[x]) return false;for (int i = 1; i + len[y] - 1 <= len[x]; i++)if (get(y, 1, len[y], 0) == get(x, i, i + len[y] - 1, 0)) return true;for (int i = 1; i + len[y] - 1 <= len[x]; i++)if (get(y, 1, len[y], 1) == get(x, i, i + len[y] - 1, 0)) return true;return false;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr); cout.tie(nullptr);cin >> n;p[0] = 1;for (int i = 1; i <= 2e4; i++) p[i] = p[i - 1] * P; for (int i = 1; i <= n; i++) {cin >> (s[i] + 1);broke_my_promise[i] = make_pair(len[i], i);len[i] = strlen(s[i] + 1);for (int j = 1; j <= len[i]; j++) hash[i][j][0] = hash[i][j - 1][0] * P + s[i][j]; // B / G -> 0 / 1?for (int j = 1; j <= len[i]; j++) hash[i][j][1] = hash[i][j - 1][1] * P + s[i][len[i] - j + 1]; // B / G -> 0 / 1?}sort(broke_my_promise + 1, broke_my_promise + 1 + n);for (int i = 1; i <= n; i++) {if (vis[i]) continue;for (int j = i + 1; j <= n; j++)vis[broke_my_promise[j].second] |= check(broke_my_promise[i].second, broke_my_promise[j].second);// my promise broken in the end...}for (int i = 1; i <= n; i++)if (!vis[i]) a[++tot] = i, sum += len[i]; // not a subcheesefor (int i = 1; i <= tot; i++)for (int j = 1; j <= tot; j++)for (int k = 0; k <= 1; k++)for (int l = 0; l <= 1; l++) {// i's end j's start for (int t = 1; t < min(len[a[i]], len[a[j]]); t++)if (get(a[i], len[a[i]] - t + 1, len[a[i]], k) == get(a[j], 1, t, l)) mx[i][j][k][l] = t;}// sum - ans...memset(f, -0x3f, sizeof(f));f[1][0][0] = 0;for (int i = 1; i < 1 << tot; i++) {for (int j = 0; j < tot; j++) { if (!(i >> j & 1)) continue;for (int k = 0; k < tot; k++) {if (i >> k & 1) continue;for (int l = 0; l <= 1; l++)for (int t = 0; t <= 1; t++)f[i | (1 << k)][k][l] = max(f[i | (1 << k)][k][l], f[i][j][t] + mx[j + 1][k + 1][t][l]);}} }for (int i = 0; i < tot; i++) {ans = max(ans, f[(1 << tot) - 1][i][0] + mx[i + 1][1][0][0]);ans = max(ans, f[(1 << tot) - 1][i][1] + mx[i + 1][1][1][0]);}cout << max(2, sum - ans) << endl;return 0;
} 
#undef int
} // namespace liuzimingc

威震逍遥津

爆搜稳定 AC。谁还写 dp 啊。当然经统计还是有三个人的。

多剪剪枝:

namespace liuzimingc {
const int N = 1e2 + 5, INF = 1e18;
#define endl '\n'int n, l, st, sum[N];
bool flag = true;
vector<pair<string, int>> e[300];
map<string, bool> vis;
string ans = "-";void dfs(string s) { // number of lowercases, can be calculated easilyif (vis[s]) return;if (islower(s[0]) && ans != "-") {if (s[0] > ans[0]) return;if (s[0] == ans[0] && s[1] > ans[1]) return;}if (1.0 * (clock() - st) / CLOCKS_PER_SEC > 0.75) return;int x = 0;for (int i = 0; i < s.length(); i++)if (islower(s[i]) || !sum[s[i]]) x++;if (l && x > l) return;vis[s] = true;bool flag = true;for (int i = 0; i < s.length(); i++)if (isupper(s[i])) {flag = false;for (const auto &j : e[s[i]])dfs(s.substr(0, i) + j.first + s.substr(i + 1));}if (flag && s.length() == l) {if (ans == "-") ans = s;else ans = min(ans, s);}
}int get_lower(string s) {int sum = 0;for (int i = 0; i < s.length(); i++)if (islower(s[i])) sum++;return sum;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr); cout.tie(nullptr);srand(490522);cin >> n >> l;st = clock();for (int i = 1; i <= n; i++) {string s;cin >> s;if (s.length() == 2) sum[s[0]] = 1;e[s[0]].push_back(make_pair(s.substr(2), get_lower(s.substr(2))));}for (int i = 'A'; i <= 'Z'; i++)random_shuffle(e[i].begin(), e[i].end());sort(e['A'].begin(), e['A'].end());dfs("S");cout << ans << endl;return 0;
} 
} // namespace liuzimingc

至于 dp 定义是神。感觉写了我也不一定会。重要的是:

实际上也可以有更粗暴的转移方法,将朴素的 dp 跑若干遍即可,正确性的证明可以考虑转移边和状态实际上构成图,转移的过程就是跑最短路,上述的过程可以看成是 SPFA 算法。

很厉害,多跑几遍就行了???和某场牛客的 dp 挺像的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/57730553.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

认知提升的方法

认知提升的方法一、什么是认知 经验是对于过往经历的总结归纳,当把这种经验传授给别人时,这种经验对别人来说就是知识。所以,知识是人脑对客观事物的信息沉淀。 技能是人们通过练习而获得的动作方式和系统,例如操作技能中的PS技术、木工技术、电工技术、水工技术等,而能力…

将社会脆弱性纳入高分辨率全球洪水风险绘图

贡献 将高分辨率流洪水模型的年平均超标概率估计值与网格化人口和贫困数据相结合,创建了 90 米分辨率的全球洪水脆弱性调整风险指数(VARI Flood)。该指数提供了国家内部或国家之间相对风险的估计值,并通过识别以高密度和高社会脆弱性为特征的 "热点地区",改变了…

acwing351

https://www.acwing.com/activity/content/problem/content/9051/ NOIP2007提高组T4。本题是加强版。 题目描述 设 \(T=(V, E, W)\) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称 \(T\) 为树网(treenetwork),其中 \(V, E\) 分别表示结点与边的集…

Unity热更学习笔记--AB包的依赖 0.98

AB包的依赖 接上一小结。 在这里我们新建一个红色材质球,赋值给Cube预制体。此时不对材质球进行AB包分类,再次进行打包。运行脚本,发现红色cube成功的从AB包中加载出来。尽管我们没有将cube所依赖的材质球进行打包分类,但是打包时候unity会自动将包中的物体相关依赖打入包中…

Y2 知识和题单

Link。 0x01 进制 引入 计数原理,对于 \(N\) 进制,那么就是逢 \(N\) 进一。 计算机中常用二进制,对应电路中的通电(\(1\))断电(\(0\))。 人类从远古以来使用十进制。 常用的有二进制、三进制、八进制、十进制、十六进制等。 由于不同进制之间数值写法可能相同,在没有特…

Clock Switch,芯片时钟切换的毛刺是什么,如何消除

背景 芯片运行过程中需要时钟切换时,要考虑到是否会产生glitch,小小的glitch有可能导致电路运行的错误。所以时钟切换时需要特别的处理。 直接使用MUX进行时钟切换或者采用如下电路结构进行时钟切换:assign outclock = (clk1 & select) | (~select & clk0);或 assig…