BZOJ 3456 权限题

太菜了推不出式子

我们设$f(n)$表示$n$个点的无向连通图的数量,那么有

$$f(n) = 2^{\binom{n}{2}} - \sum_{i = 1}^{n - 1}\binom{n - 1}{i - 1}f(i)2^{\binom{n - i}{2}}$$

思路就是全部减去不合法的,枚举$1$号点所在的联通块的大小,剩下随便生成一张无向图。

拆开组合数,简单变形一下

$$f(n) = 2^{\binom{n}{2}} - (n - 1)!\sum_{i = 1}^{n - 1}\frac{2^{\binom{n - i}{2}}}{(n - i)!}\frac{f(i)}{(i - 1)!}$$

记$h(i) = \frac{f(i)}{(i - 1)!}$,$g(i) = \frac{2^{\binom{i}{2}}}{i!}$

$$(n - 1)!h(n) = 2^{\binom{n}{2}} - (n - 1)!\sum_{i = 1}^{n - 1}g(i)h(n - i)$$

发现这个式子可以用分治FFT优化,直接上就做完了。

时间复杂度$O(nlog^2n)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 3e5 + ;
const ll P = 1004535809LL; int n, lim, pos[N];
ll f[N], g[N], fac[N], inv[N], a[N], b[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline ll fpow(ll x, ll y) {
ll res = ;
for (; y > ; y >>= ) {
if (y & ) res = res * x % P;
x = x * x % P;
}
return res;
} template <typename T>
inline void swap(T &x, T &y) {
T t = x; x = y; y = t;
} inline void prework(int len) {
int l = ;
for (lim = ; lim <= len; lim <<= , ++l);
for (int i = ; i < lim; i++)
pos[i] = (pos[i >> ] >> ) | ((i & ) << (l - ));
} inline void ntt(ll *c, int opt) {
for (int i = ; i < lim; i++)
if (i < pos[i]) swap(c[i], c[pos[i]]);
for (int i = ; i < lim; i <<= ) {
ll wn = fpow(, (P - ) / (i << ));
if (opt == -) wn = fpow(wn, P - );
for (int len = i << , j = ; j < lim; j += len) {
ll w = ;
for (int k = ; k < i; k++, w = w * wn % P) {
ll x = c[j + k], y = w * c[j + k + i] % P;
c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
}
}
} if (opt == -) {
ll invP = fpow(lim, P - );
for (int i = ; i < lim; i++) c[i] = c[i] * invP % P;
}
} inline ll getC(int x) {
if (x < ) return ;
return (1LL * x * (x - ) / );
} void solve(int l, int r) {
if (l == r) {
f[l] = (fpow(, getC(l) % (P - )) - f[l] * fac[l - ] % P + P) % P;
f[l] = f[l] * inv[l - ] % P;
return;
} int mid = ((l + r) >> );
solve(l, mid); prework(r - l + );
for (int i = ; i < lim; i++) a[i] = b[i] = 0LL;
for (int i = l; i <= mid; i++) a[i - l] = f[i];
for (int i = ; i <= r - l; i++) b[i - ] = g[i];
ntt(a, ), ntt(b, );
for (int i = ; i < lim; i++) a[i] = a[i] * b[i] % P;
ntt(a, -); for (int i = mid + ; i <= r; i++)
f[i] = (f[i] + a[i - l - ] % P) % P; solve(mid + , r);
} int main() {
read(n); fac[] = 1LL;
for (int i = ; i <= n; i++) fac[i] = fac[i - ] * i % P;
inv[n] = fpow(fac[n], P - );
for (int i = n - ; i >= ; i--) inv[i] = inv[i + ] * (i + ) % P; for (int i = ; i <= n; i++)
g[i] = fpow(2LL, getC(i) % (P - )) * inv[i] % P; solve(, n); printf("%lld\n", f[n] * fac[n - ] % P);
return ;
}

最新文章

  1. ubuntu wifi连接不上或经常断网,重启就好
  2. LeetCode Total Hamming Distance
  3. SQL更改表字段为自增标识
  4. ubuntu vsftp 安装
  5. SpringMVC配置入門
  6. Android中style的使用
  7. 数据的存储-NSKeyedArchiver和write to file介绍
  8. UVA 408 (13.07.28)
  9. USACO Section 1.3 Mixing Milk 解题报告
  10. Linux 菜鸟学习笔记--系统分区
  11. java 关于 hashmap 的实现原理的测试
  12. getnameinfo函数
  13. less的安装与用法
  14. MySQL两种存储引擎: MyISAM和InnoDB 简单总结
  15. bzoj1019 / P4285 [SHOI2008]汉诺塔
  16. Linux-IO重定向与管道
  17. InstallShield打包,以及集成TFS、JenKins
  18. SNMP学习笔记之SNMP TRAP简介、流程以及使用Python实现接受Trap信息
  19. nginx 学习笔记(2) nginx新手入门
  20. 20165324 《Java程序设计》 第六周

热门文章

  1. Visual Studio 2013 帮助文档 安装以及如何直接打开
  2. LeetCode Kill Process
  3. 【模板】NOIP模板汇总
  4. add-apt-repository 添加
  5. Oracle中exp,imp(导入导出)数据迁移注意事项
  6. ArcGIS破解配置及oracle文件配置
  7. RbbitMQ基础知识
  8. junit基础学习
  9. dxjk服务器安装 lamp
  10. Oracle 12.1.0.2 对JSON的支持