840C - On the Bench

题意

给定序列 a[1...n]a[1...n]a[1...n],求有多种 aaa 的排列,满足任意两个相邻的数乘积不是完全平方数,答案对 109+710^9+7109+7 取模。

ai≤109,1≤n≤300a_i\le 10^9,\ 1\le n \le 300ai​≤109, 1≤n≤300

转换

如果 xy=p2xy=p^2xy=p2,yz=q2yz=q^2yz=q2,那么 xz=(pqx)2xz=({\dfrac{pq}{x}})^2xz=(xpq​)2,也是一个完全平方数。所以我们可以把把 x,y,zx,y,zx,y,z 视为一个同一种颜色,以此类推……用并查集维护每一种颜色的数量。

于是问题转换为:

有 mmm 种颜色的球,第 iii 种颜色的球有 sis_isi​ 种,总共 nnn 个球,求同色不相邻的排列的数量。

DP + 容斥 O(n2)O(n^2)O(n2)

本方法参考 这篇博客。

设 f(k)f(k)f(k) 表示把这些小球分成 kkk 个连续段的方案数,其中:

  • 每一段都是相同的颜色;
  • 段内小球考虑排列顺序;
  • 段与段之间无序,即所有的段构成一个无序集合。

下面用 DP 来求 f(k)f(k)f(k)。

设 f(i,k)f(i,k)f(i,k) 表示考虑前 iii 种颜色,分成了 kkk 组的方案数。容易推出 fff 的转移方程
f(i,k)=∑j=1min⁡(si,k)f(i−1,k−j)⋅si!⋅(si−1j−1)j!f(i,k) = \sum_{j=1}^{\min(s_i, k)}f(i-1,k-j)\cdot \dfrac{s_i!\cdot{s_i-1\choose j-1}}{j!} f(i,k)=j=1∑min(si​,k)​f(i−1,k−j)⋅j!si​!⋅(j−1si​−1​)​

简要介绍这个式子的含义。

枚举最后一种颜色(第 iii 种颜色)分成了 jjj 段,所以由 f(i−1,k−j)f(i-1,k-j)f(i−1,k−j) 转移过来。

si!s_i!si​! 是将 sis_isi​ 个同色小球排列,然后 (si−1j−1){s_i-1\choose j-1}(j−1si​−1​) 是将这个排列分成 kkk 个段(原理是隔板法)。由于组与组是无序的,所以要除以 j!j!j!。

那么 f(n,k)f(n,k)f(n,k) 就是将所有的小球分为 kkk 组的方案数,简要记为 f(k)f(k)f(k)。

特别注意一下这个 DP 式子的复杂度,它虽然是三重循环,但神奇的是它的复杂度其实是 O(n2)O(n^2)O(n2) 。因为第一层循环的是颜色,第三层循环的次数不超过该种颜色的数量,所以这两层循环的总次数其实是 ∑i=mnsi\sum_{i=m}^{n}s_i∑i=mn​si​,这两层和一块是 O(n)O(n)O(n) 级别的。

如果把所有小球分为 kkk 组,那么至少有 n−kn-kn−k 对相邻的同色小球。

所以 f(n)⋅n!f(n)\cdot n!f(n)⋅n! 就是提前钦定 n−kn-kn−k 对同色小球,其余随意组合的方案数之和。这样答案就是典型的容斥
ans=f(n)⋅n!−f(n−1)⋅(n−1)!+…ans=f(n)\cdot n! - f(n-1)\cdot(n-1)! + \dots ans=f(n)⋅n!−f(n−1)⋅(n−1)!+…

#include <bits/stdc++.h>
using namespace std;#define int long long
#define PII pair<int, int>int Testnum = 1;/**********************  Core code begins  **********************/const int N = 1003, MOD = 1e9 + 7;
int n, a[N];
int fac[N], inv[N], invfac[N];
int m = 0, s[N], f[N][N];struct DSU {int fa[N], siz[N];void init() {for (int i = 1; i < N; i++) {fa[i] = i;siz[i] = 1;}}int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}void merge(int x, int y) {if (find(x) == find(y)) {return;}int fx = find(x), fy = find(y);fa[fx] = fy;siz[fy] += siz[fx];}
} dsu;void init() {fac[0] = inv[0] = invfac[0] = 1;fac[1] = inv[1] = invfac[1] = 1;for (int i = 2; i < N; i++) {fac[i] = fac[i - 1] * i % MOD;inv[i] = ((MOD - MOD / i * inv[MOD % i]) % MOD + MOD) % MOD;invfac[i] = invfac[i - 1] * inv[i] % MOD;}
}int C(int x, int y) {if (x < y || x < 0) {return 0;}return fac[x] * invfac[y] % MOD * invfac[x - y] % MOD;
}void SolveTest() {cin >> n;dsu.init();init();for (int i = 1; i <= n; i++) {scanf("%lld", &a[i]);}for (int i = 1; i <= n; i++) {for (int j = i + 1; j <= n; j++) {int x = sqrt(a[i] * a[j]);if (x * x == a[i] * a[j]) {dsu.merge(i, j);}}}m = 0;for (int i = 1; i <= n; i++) {if (dsu.fa[i] == i) {s[++m] = dsu.siz[i];}}f[0][0] = 1;for (int i = 1; i <= m; i++) {for (int k = i; k <= n; k++) {for (int j = 1; j <= min(s[i], k); j++) {f[i][k] = (f[i][k] + f[i - 1][k - j] * fac[s[i]] % MOD * C(s[i] - 1, j - 1) % MOD * invfac[j] % MOD) % MOD;}}}int res = 0, sig = 1;for (int i = n; i >= 1; i--) {res = (res + sig * f[m][i] % MOD * fac[i] % MOD) % MOD;sig = MOD - sig;}cout << res;
}/**********************  Core code ends  ***********************/signed main() {#ifdef LOCALfreopen("in.txt", "r", stdin);
#endif// cin >> Testnum;for (int i = 1; i <= Testnum; i++) {SolveTest();}return 0;
}

840C - On the Bench (容斥 + DP)相关推荐

  1. LOJ#3124. 「CTS2019 | CTSC2019」氪金手游 容斥+DP

    神仙容斥+DP可还行. code: #include <cstdio> #include <cmath> #include <vector> #include &l ...

  2. 洛谷P3349:小星星(容斥dp)

    解析 先安利一波洛谷上我介绍如何用暴力日过去的博客 现在开始务正业 考虑把dp记录状态的一维s去掉 这样单次转移复杂度变成n3n^3n3 但是这样显然会算多啊! 因为一个编号可能会用很多次 考虑容斥 ...

  3. P4707 重返现世 扩展 MinMax 容斥+DP

    题目传送门 https://www.luogu.org/problem/P4707 题解 很容易想到这是一个 MinMax 容斥的题目. 设每一个物品被收集的时间为 \(t_i\),那么集齐 \(k\ ...

  4. 洛谷P4707 重返现世(扩展MinMax容斥+dp)

    传送门 我永远讨厌\(dp.jpg\) 前置姿势 扩展\(Min-Max\)容斥 题解 看纳尔博客去→_→ 咱现在还没搞懂为啥初值要设为\(-1\)-- //minamoto #include< ...

  5. P5643-[PKUWC2018]随机游走【min-max容斥,dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P5643 题目大意 给出nnn个点的一棵树,一个人从点xxx开始随机游走,然后QQQ次询问给出一个点集SSS,求期望 ...

  6. ARC115E-LEQ and NEQ【容斥,dp,线段树】

    正题 题目链接:https://atcoder.jp/contests/arc115/tasks/arc115_d 题目大意 nnn个数字的序列xxx,第xi∈[1,Ai]∩Zx_i\in [1,A_ ...

  7. P4859-已经没有什么好害怕的了【容斥,dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P4859 题目大意 两个长度为nnn的序列a,ba,ba,b两两匹配,求ai>bia_i>b_iai​& ...

  8. 牛客练习赛71C-数学考试【容斥,dp】

    正题 题目链接:https://ac.nowcoder.com/acm/contest/7745/C 题目大意 求一nnn的排列,给mmm个限制pip_ipi​表示1∼pi1\sim p_i1∼pi​ ...

  9. Codeforces 1043F(容斥+dp)

    题目链接 题意 是否存在选择方案使所选的数$gcd=1$ 思路 $f[i][j]$表示选$i$个数$gcd=j$的方案数,$cnt[i]$表示包含因子$i$的数的个数,则$f[i][j]=$$C_{c ...

最新文章

  1. JavaScript(3)之——对象的属性描述符
  2. css的checkbox样式变化
  3. poj 1270(toposort)
  4. C#实现动态编译代码
  5. jQuery无任何标示获取td在表格中的行数和列数
  6. mysql事务隔离级别详解_高性能MySQL-详解事务与隔离级别
  7. 职场中 你要学习12种动物精神
  8. 同一个字体,不同平台完全不同
  9. adb 安卓模拟器 进程端口_Frida初体验安卓CTF逆向
  10. COM 组件编程--VC知识库读杨老师文章笔记
  11. 防止SQL注入的五种方法
  12. 8051RTX编程一例
  13. post请求测试软件,简单的Http请求测试工具(支持get,post)
  14. Sat Sep 25 07:38:46 Local time zone must be set--see zic manual page 2021
  15. 2021年杭州值得去的46家规模互联网大厂公司全名简称
  16. CF 614 C Peter and Snow Blower (海伦公式、n个顶点绕圆扫过的最大面积)
  17. Hive-时间日期trunc-日期与数字截取函数
  18. 小程序中实现关注公众号
  19. E212: 无法打开并写入文件
  20. 诊断CAPL自动化(8)——封装的读取/检查DTC函数库,覆盖了所有的测试场景

热门文章

  1. html怎样设置下一页,用Dreamweaver做网页 如何设置“下一页、上一页”?
  2. ios(ipod touchipadiphone)越狱后的工作
  3. AJAX无法找到不执行或者报错原因时?你该这样做
  4. 华为HiLink 云云对接 后台开发的一些细节和坑
  5. 一起来学习在Ubuntu上安装Budgie桌面
  6. cct 二级java复习资料_年第一次全国高校安徽考区计算机水平考试(CCT)
  7. WindowBlinds破解全书
  8. 股票通达信软件常用设置(1)
  9. Win7提速如何进行磁盘清理和碎片整理
  10. 如何写出高效的SQL脚本