[AtcoderABC200E]Patisserie

[AtcoderABC200E]Patisserie

题面翻译

对于一个三元组\((i,j,k)\) 我们对它按如下要求进行升序排序:

  • 第一关键词 \(i + j + k\) 即三者总和

  • 第二关键词 \(i\)

  • 第三关键词 \(j\)

特别的 我们给出了\(n\)
对于任何一个三元组\((i,j,k)\ i\in[1,n], j\in[1,n], k\in[1,n]都存在\)

现在给出\(P\) 求出排名为P的三元组的具体元素 即\((i,j,k)\)

\(n \leq 10^6\ \ k \leq 10^3\)

思路

类似于Contor展开的排列计数方法

也就是试填法

即枚举每一项元素 通过函数\(calc()\)计算该项排列或是数列的个数

根据排名快速确定每一位元素

现在的问题就是如何实现\(calc()\)

你可以通过打表 或是 硬推 得到一部分思路

根据第一个条件先确定第一位 (因为总和确定后面就好搞了

很容易可以发现

第一个条件就是再求

\[\begin{cases} i + j + k = x \i \leq n \j \leq n \k \leq n \\end{cases} \]

的方案数

那么 随便 一算可以推出方案数

\[g(x)= \begin{cases} 0,\quad x\in(-\infty,3)\cup(3n,\infty) \\frac{(x-1)(x-2)}{2},\quad x\in[3,3n] \end{cases} \]

或者说是

\[\left( \begin{matrix} x-1 \2 \\end{matrix} \right) \]

然后我们考虑一下加上限制

加上其中一项 就把它减去n算一下之前的g(x)

\(g(x - n)\) 也就是

\[\left( \begin{matrix} x-n \2 \end{matrix} \right) \]

然后可以随意加其中一个 共有三种方案 系数为-3

任选其中两项、三项(好像用不到)同理

那么真正的方案书\(f(x)\)也就是

\[f(x) = g(x) - 3g(x - n) + 3g(x - 2n) - g(x - 3n) \]

补充:

这里还有一种DP写法 可能会好理解一些

本文就不再赘述 请读者自行思考或查阅

总结

这道题放在定位为普及模拟赛T2令人着实很吃惊

主要是时间较紧也就成了选手实力的分水岭

要看能不能往组合数的角度(插板法 也许吧)去想了

俺比赛的时候推出第一个式子以为是高阶等差数列 就开始没推出来

还是经验太少了 毕竟OI的数学题还是相对挺少的

Code

说实话真的短 就是思路挺妙的

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>

using namespace std;

#define int long long

int read(int x = 0, bool f = false, char ch = getchar()) {
	for (; !isdigit(ch); ch = getchar()) f |= (ch == ‘-‘);
	for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
	return f ? ~x + 1 : x;
}

int g(int x) {return x <= 2? 0 : ((x - 1) * (x - 2)) / 2;}

int f(int x, int y) {return g(x) - 3 * g(x - y) + 3 * g(x - 2 * y) - g(x - 3 * y);}

int n, k;

signed main() {
//	freopen("cake.in", "r", stdin);
//	freopen("cake.out", "w", stdout);
	n = read(), k = read();
	for (int i = 3; i <= 3 * n; ++i) {
		if (k <= f(i,n)) {
			for (int j = 1; j <= n; ++j) {
				int mn = max(1ll, i - j - n), mx = min(n, i - j - 1ll);
				if (mx < mn) continue;
				if (k <= mx - mn + 1)
					return printf("%lld %lld %lld\n", j, mn + k - 1, i - j - mn - k + 1), 0;
				k -= mx - mn + 1;
			}
		} else k -= f(i,n);
	}
} 

[AtcoderABC200E]Patisserie

上一篇:K8s 部署 Gitlab CI Runner


下一篇:包装类