2022.10.12 闲话

i want to make a public contest

看了一下 cppreference 的 dependent nameODR 规则ADL,深感 C++ 之牛逼啊 .

选两个比较高级的绝世好题:

  • 给定一棵有根树,动态加点,支持换根,实时查询重链剖分的链数(多个重儿子取编号最小) — fhqtreap
  • 给你一个二分图,请求出它的七元环数量 — dottle(这个好像骗过 joke3579).

如何出一道诈骗题呢?

Calc

给一个正整数 \(n\),求

\[\sum_{j=2}^n\left\lfloor\dfrac{(j-1)!+1}{j}-\left\lfloor\dfrac{(j-1)!}{j}\right\rfloor\right\rfloor \]

\(1\le n\le 10^{12}\) .

Koishi Loves Construction

给一个 \(n\),要求:

  • Task 1:试判断能否构造并构造一个长度为 \(n\)\(1 \dots n\) 的排列,满足其 \(n\) 个前缀和在模 \(n\) 的意义下互不相同 .
  • Task 2:试判断能否构造并构造一个长度为 \(n\)\(1 \dots n\) 的排列,满足其 \(n\) 个前缀积在模 \(n\) 的意义下互不相同 .

如果能构造,构造一组方案 .

\(1\le n\le 10^5\) .

lambda 表达式实现递归的几种方案 (C++)

为什么 Python 的 lambda 表达式能直接使用递归啊?

以下 [&][=][] 不做区分(随便用 hhh).

以下的实例用一个简单递归函数演示

int f(int x){return x < 1 ? 0 : f(x-1) + 1;}

1. 使用 std :: function 包装

就是用 std :: function 包装后它就不是匿名的了,后面该咋写咋写就完了 .

类似于 C# 的

Func<int, int> f = null;
f = x => x < 1 ? 0 : f(x-1) + 1;

第一句就是先把它放着(声明)然后再用,当然这个做法在 C# 是有一定缺陷的(因为 C# 特性),但是在 C++ 里没有 .

一份实现:

auto f = [](int n)
{
	std :: function<int(int)> _;
	_ = [&](int n){return n < 1 ? 0 : 1 + _(n-1);}; 
	return _(n);
};

好像后面的做法都要 since C++14 .

2. 将自身作为参数传入

这个是最常用且最简单的了 .

不多说,直接放代码:

auto f = [](auto&& self, int x){return x < 1 ? 0 : self(self, x-1) + 1;};

传的时候要传一下 self,别的就没有什么太大的缺点了 .

3. 使用 Generic Lambda 代替方法 2 中传参

这个是最方便的了 .

std :: function<int(int)> f = [&f](int n){return n < 1 ? 0 : f(n-1) + 1;};

这里不能用 auto,因为这里的类型相当于递归了,auto 的话编译器推不出来类型 .

其实 Generic Lambda 就相当于带 template 的 lambda 表达式 .

4. 使用 Y Combinator

具体需要一些 \(\lambda\) 演算的知识,可以去 Wikipedia 看一下 Lambda Calculus,\(\alpha\text{-}\rm equivalent\)\(\beta\text{-}\rm{reduction}\)\(\eta\text{-}\rm{conversion}\) 等 .

我们知道 Y 组合子(Y Combinator)是不动点组合子的一种,因为 Y 组合子相比其他不动点组合子非常容易实现所以采用 Y 组合子 .

Y 组合子:λf.(λx.f(x x))(λx.f(x x)) .

翻译成 C++(下面是一个 std :: function<int(int)> 版本的):

auto y = [](auto f)
{
	return [&](auto _){return _(_);}([&](const auto& rec) -> std :: function<int(int)>
	{
		return f([&](int arg){return rec(rec)(arg);});
	});
};

使用只需要传入一个原函数的高阶函数即可:

auto inr = [](auto f){return [&](int n){return n < 1 ? 0 : f(n-1) + 1;};};
printf("%d\n", y(inr)(114514)); // 别爆栈了 /hsh

posted @ 2022-10-12 19:56  Jijidawang  阅读(83)  评论(3编辑  收藏  举报
😅​