标签:tps 机器人 bin machine can 差分 题目 std print
这场比赛是我自己找的我没做过的题,我给我自己出的比赛(我可以随便更改总时间。。)。
这是一道有思维含量的计数题
有 \(n\) 个排成一行的格子。前 \(n-1\) 个位置有机器人。每个机器人会涂向后两个格子。每个机器人都运作一遍算是一种涂法,它的贡献为最后一个涂上的格子是第几次涂的。
很容易想到,如果得到贡献为 \(i\) 的排列方法数量,就解决了。但是这并不好得到。所以考虑求 \(f_i\) 表示 \(i\) 步已经涂完的方案数量。这样差分一下就可以得到贡献为 \(i\) 的排列方法数量了。
首先,必然第一个机器人。如果得到一共有多少个选择机器人的方案,那么乘上排列机器人与剩下机器人的排列方案数就是答案了。所以问题转化为如何得到一共有多少个选择机器人的方案,使得它可以覆盖所有的格子。考虑将所有机器人按照起始位置排序,那么考虑从小到大将每个机器人逐个添加。添加过程中,每个机器人至少能多涂一个格子,至多涂两个格子。如果确定每一次添加机器人能多多少个格子,那么可以唯一对应一种每个位置的机器人选不选的方案。如果我们知道一共涂了多少次就涂完了,那么就可以求出一共有多少次添加机器人能够多1个格子,有多少次能够多2个格子。所以设有 \(x\) 个多一个格子的,\(y\) 个多两个格子的。那么方案数为 \(\binom{x+y}{x}\)。然后乘上系数就完了。
关键在于找到一个合适的对应关系。一个+1,+2组成的数列可以对应一个机器人选不选的方案。
#include <cstdio>
using namespace std;
const int N = 1e6 + 5, Mod = 1e9 + 7;
int ml(int x, int y) { return 1ll * x * y % Mod; }
int dc(int x, int y) { return (x - y < 0) ? (x - y + Mod) : (x - y); }
int ad(int x, int y) { return (x + y > Mod) ? (x + y - Mod) : (x + y); }
int n, f[N], fac[N], inv[N];
int ksm(int x, int y) {
int ret = 1;
for (; y; y >>= 1, x = ml(x, x))
if (y & 1) ret = ml(ret, x);
return ret;
}
void Prepare() {
fac[0] = 1;
for (int i = 1; i <= n; ++i) fac[i] = ml(fac[i - 1], i);
inv[n] = ksm(fac[n], Mod - 2);
for (int i = n - 1; i >= 0; --i) inv[i] = ml(inv[i + 1], i + 1);
}
int binom(int u, int d) {
if (u < 0 || d < 0) return 0;
if (u < d) return 0;
return ml(fac[u], ml(inv[d], inv[u - d]));
}
int main() {
scanf("%d", &n);
Prepare();
for (int i = 1; i <= n - 1; ++i)
f[i] = ml(binom(i - 1, n - i - 1), ml(fac[i], fac[n - i - 1]));
for (int i = n - 1; i >= 1; --i) f[i] = dc(f[i], f[i - 1]);
int ans = 0;
for (int i = 1; i <= n - 1; ++i) ans = ad(ans, ml(f[i], i));
printf("%d\n", ans);
return 0;
}
标签:tps 机器人 bin machine can 差分 题目 std print
原文地址:https://www.cnblogs.com/skiceanAKacniu/p/13233092.html