博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[CSA] Number Elimination
阅读量:5154 次
发布时间:2019-06-13

本文共 2463 字,大约阅读时间需要 8 分钟。

Solution

要求最小代价的方案数,所以我们显然可以直接把这些元素从小到大排序

我们令\(f_i\)表示消去\(i\)个一样的数字的方案数,不难得出\(f_i = \frac {i \cdot (i - 1)} {2} f_{i - 1}\)

假设当前有\(i\)个数字,我们可以任选两个数字把编号小的消去,所以方案数为\(i \choose 2\)

然后就转化成\(i - 1\)个数字的局面了

把值相等的数字分为一组,设\(len_i\)表示第\(i\)组数字的个数,设\(sum_i\)表示前\(i\)数字的总长度,\(dp_i\)表示消去前\(i\)组的方案数,则有:

\[ dp_i = dp_{i - 1} \cdot f_{len_i} \cdot \sum _{j = 0} ^ {j = len_i - 1} {
{sum_{i - 1} - 1 + j} \choose j} \cdot (len_i - j) \]

前面乘了一个\(f_{len_i}\)表示已经考虑了本组的内部消除顺序

组合数表示删掉前面的所有数(除上组最后一个)以及当前组的任意\(j\)个数的先后顺序方案数

最后后面那个式子表示上组最后一个可以被当前组剩下未删的任意一个数消去

Code

#include 
using namespace std;#define fst first#define snd second#define squ(x) ((LL)(x) * (x))#define debug(...) fprintf(stderr, __VA_ARGS__)typedef long long LL;typedef pair
pii;inline int read() { int sum = 0, fg = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1; for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30); return fg * sum;}const int maxn = 1e5 + 10;const int mod = 1e9 + 7;inline int add(int x, int y) { return (x += y) < mod ? x : x - mod; }inline int mul(LL x, int y) { return (LL)x * y % mod; }int Pow(int x, int y) { int res = 1; while (y) { if (y & 1) res = mul(res, x); x = mul(x, x); y >>= 1; } return res;}int n, N, a[maxn], len[maxn], sum[maxn], dp[maxn], f[maxn];int fac[maxn], ifac[maxn];inline int C(int _n, int _m) { return mul(fac[_n], mul(ifac[_n - _m], ifac[_m])); }void init() { fac[0] = 1; for (int i = 1; i <= n; i++) fac[i] = mul(fac[i - 1], i); ifac[n] = Pow(fac[n], mod - 2); for (int i = n - 1; ~i; i--) ifac[i] = mul(ifac[i + 1], i + 1);}int main() {#ifdef xunzhen freopen("out.in", "r", stdin); freopen("out.out", "w", stdout);#endif n = read(); init(); for (int i = 1; i <= n; i++) a[i] = read(); sort(a + 1, a + n + 1); int pos = 1; for (int i = 2; i <= n + 1; i++) if (a[i] != a[i - 1]) len[++N] = i - pos, sum[N] = sum[N - 1] + len[N], pos = i; f[1] = 1; for (int i = 2; i <= n; i++) f[i] = mul(f[i - 1], mul(mul(i, i - 1), ifac[2])); dp[1] = f[len[1]]; for (int i = 2; i <= N; i++) { int Sum = 0; for (int j = 0; j < len[i]; j++) Sum = add(Sum, mul(C(sum[i - 1] - 1 + j, j), len[i] - j)); dp[i] = mul(mul(dp[i - 1], f[len[i]]), Sum); } printf("%d\n", dp[N]); return 0;}

Summary

这个DP的思维好神啊,完全想不到 考试的时候部分分都打挂了

转载于:https://www.cnblogs.com/xunzhen/p/9844682.html

你可能感兴趣的文章
https://blog.csdn.net/u012106306/article/details/80760744
查看>>
海上孤独的帆
查看>>
处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“Manag
查看>>
01: socket模块
查看>>
mysql触发器
查看>>
淌淌淌
查看>>
win10每次开机都显示“你的硬件设置已更改,请重启电脑……”的解决办法
查看>>
C++有关 const & 内敛 & 友元&静态成员那些事
查看>>
函数积累
查看>>
Swift 入门之简单语法(六)
查看>>
〖Python〗-- IO多路复用
查看>>
栈(括号匹配)
查看>>
Java学习 · 初识 面向对象深入一
查看>>
源代码如何管理
查看>>
vue怎么将一个组件引入另一个组件?
查看>>
bzoj1040: [ZJOI2008]骑士
查看>>
LeetCode 74. Search a 2D Matrix(搜索二维矩阵)
查看>>
利用SignalR来同步更新Winfrom
查看>>
反射机制
查看>>
CocoaPod
查看>>