Lambda 在竞赛的简单应用

该死的 CCF 终于更新到了 c++14。 __gcdauto 以外,Lambda 也可以优化码风,对 Oier 还是挺有用的。

Lambda表达式是现代C++在C ++ 11和更高版本中的一个新的语法糖 ,在C++11、C++14、C++17和C++20中Lambda表达的内容还在不断更新。 lambda表达式(也称为lambda函数)是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。——这里

Lambda 是一种在调用等地定义的匿名函数。非常简单,相信看两个例子你就能理解。


假如你定义了一个结构体:

1
2
3
struct node {
int x, y;
}a[N];

要对其进行排序,你可能会定义一个 cmp 函数,或是重载运算符,它们长这样:

1
2
3
4
bool cmp(node a, node b) {
return a.x < b.x;
}
sort(a + 1, a + n + 1, cmp);
1
2
3
4
5
6
7
struct node {
int x, y;
bool operator <(const node &o) const {
return x < o.x;
}
}a[N];
sort(a + 1, a + n + 1);

使用 Lambda 就可以这样写:

1
sort(a + 1, a + n + 1, [](node a, node b){return a.x < b.x;});

可以看到,Lambda 珂以使代码更加简洁易懂。

这里的 Lambda 也很好理解,[] 是 Lambda 的标识,也用来让 Lambda 使用外部变量,在下面的例子还会提到。

(node a, node b) 是传入的参数,{return a.x < b.x} 即函数主体,这与普通函数没有区别。

这个匿名函数省略的很多内容,但对于 Oier 来说也没有必要使用。其实就是我不会

再来看第二个例子。


想象这样的代码场景,多个循环嵌套,在一波操作后你需要直接跳出多重循环。这个问题也困扰了我一段时间,如何写得简洁优雅?

一种写法是定义布尔变量配合break

1
2
3
4
5
6
7
8
9
10
11
12
13
for (...) {
bool b = 0;
for (...) {
for (...) {
if (...) {
b = 1;
break;
}
}
if (b) break;
}
if (b) break;
}

略丑 /jk。

也会有人使用 goto

1
2
3
4
5
6
7
8
for (...) {
for (...) {
for (...) {
if (...) goto T;
}
}
}
T:;

这样就很美观,但我们都知道一位老头计算机科学家提出了 goto 有害论,所以用的时候总感觉很不爽,有种玩火焚身的感觉。那么 Lambda 表现如何呢?

1
2
3
4
5
6
7
8
9
[&]() {
for (...) {
for (...) {
for (...) {
if (...) return;
}
}
}
}();

将整个循环套在一个函数里,这样就可以直接使用 return 跳出。虽然比不上 goto简洁,但看起来还是很不错的。这里比刚才多了点东西,我们来康康。

中括号里面多了个&这个符号用于使 Lambda 可以调用、更改函数外部的变量(闭包);Lambda 外面多了个圆括号,这个很好理解,在定义完后直接调用函数。

这是两个简单的例子,现在您应该会使用简单的 Lambda 了吧。

再不会我也没办法了 我也就会那么多了

  • 补充一点,你可以这样写:
1
2
auto F = [](/*...*/){/*...*/};
F();

UPDATE 20.5.16

在那种状态很多、很多循环转移又很相似的 dp 题中,Lambda 配合 #define rep 有奇效。

e.g

AcWing 321.棋盘分割

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <bits/stdc++.h>
using namespace std;

inline int read() {
int x = 0, f = 0; char c = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c & 15), c = getchar();
return f ? -x : x;
}

#define rep(i, a, b) for (int i = (a); i <= (b); i ++)

#define N 10
#define M 20
#define INF 1e9

int n, m, a[N][N], s[N][N];
double f[M][N][N][N][N];

int main() {
n = 8, m = read() - 1;
rep(i, 1, n) rep(j, 1, n) s[i][j] = a[i][j] = read();
rep(i, 1, n) rep(j, 1, n) s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];

double bX = 1.0 * s[n][n] / (m + 1);
rep(i, 1, n) rep(j, 1, n) rep(k, i, n) rep(l, j, n) {
f[0][i][j][k][l] = s[k][l] - s[i - 1][l] - s[k][j - 1] + s[i - 1][j - 1] - bX;
f[0][i][j][k][l] = f[0][i][j][k][l] * f[0][i][j][k][l];
}

rep(d, 1, m) rep(len, 1, n) rep(i, 1, n) rep(j, 1, n) {
auto F = [&f, &s](int d, int i, int j, int k, int l) {
double &now = f[d][i][j][k][l]; now = INF;
rep(a, i, k - 1) {
now = min(now, f[d - 1][i][j][a][l] + f[0][a + 1][j][k][l]);
now = min(now, f[0][i][j][a][l] + f[d - 1][a + 1][j][k][l]);
}
rep(b, j, l - 1) {
now = min(now, f[d - 1][i][j][k][b] + f[0][i][b + 1][k][l]);
now = min(now, f[0][i][j][k][b] + f[d - 1][i][b + 1][k][l]);
}
};
if (j + len - 1 <= n) rep(k, i, n) F(d, i, j, k, j + len - 1);
if (i + len - 1 <= n) rep(l, j, n) F(d, i, j, i + len - 1, l);
}

printf("%.3lf\n", sqrt(f[m][1][1][n][n] / (m + 1)));
return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!