题目链接

ZOJ3874

题意简述:

在一个序列中,两点间如果有边,当且仅当两点为逆序对

给定一个序列的联通情况,求方案数对\(786433\)取模

题解

自己弄了一个晚上终于弄出来了

首先\(yy\)一下发现一个很重要的性质:

联通块内的点编号必须是连续的

证明:

假设一个联通块编号不连续,设\(a\),\(b\)分别为联通块左侧和联通块右侧中的一个点,\(x\)为\(a\),\(b\)之间不在该联通块内的点

那么显然有\(a > b\),\(a < x\),\(x < b\)

即\(a < x < b\)的同时\(a > b\)

不符

故一个联通块内的编号必须连续

证毕

好了我们有了这样一个性质,那么假设他给我们的联通块不符合这个条件,就直接输出\(0\)【一定要记得,我就是一直挂在这个\(sb\)地方调了半天QAQ】

然后如果符合条件,我们就要计算方案数了

因为联通块已经被分成一段一段,所以任意两个联通块之间一定是递增的,互不干涉

所以我们只需要计算出\(f[i]\)表示\(i\)个点联通块的方案

按套路,我们补集转化,并枚举第一个点所在联通块大小

\[f[n] = n! - \sum\limits_{i = 1}^{n - 1} f[i](n - i)!
\]

\(n!\)是总方案,前\(i\)个点联通方案是\(f[i]\),按照性质,前\(i\)个点一定是前\(i\)小的点,与后面\(n - i\)个点没有任何关联,所以后面\(n - i\)个点可以任意排布

这样我们就可以分治\(NTT\)在\(O(nlog^2n)\)的时间内预处理出\(f[i]\)

然后询问的时候根据乘法原理计算即可

时间复杂度\(O(nlog^2n + Tn)\)

如果您常数比较大,就需要优化一下,比如循环展开大法好

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (register int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define res register
using namespace std;
const int maxn = 400005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
const int G = 10,P = 786433;
int R[maxn],c[maxn],w[maxn];
inline int qpow(int a,int b){
int re = 1;
for (; b; b >>= 1,a = 1ll * a * a % P)
if (b & 1) re = 1ll * re * a % P;
return re;
}
void NTT(int* a,int n,int f){
for (res int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
for (res int i = 1; i < n; i <<= 1){
int gn = w[i];
for (res int j = 0; j < n; j += (i << 1)){
int g = 1,x,y;
for (res int k = 0; k < i; k++,g = 1ll * g * gn % P){
x = a[j + k],y = 1ll * g * a[j + k + i] % P;
a[j + k] = (x + y) % P,a[j + k + i] = ((x - y) % P + P) % P;
}
}
}
if (f == 1) return;
int nv = qpow(n,P - 2); reverse(a + 1,a + n);
for (res int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv % P;
}
int fac[maxn],fv[maxn],N = 100000;
int f[maxn],A[maxn],B[maxn];
void solve(int l,int r){
if (l == r){f[l] = ((fac[l] - f[l]) % P + P) % P; return;}
int mid = l + r >> 1;
solve(l,mid);
int n,m,L = 0; n = mid - l;
for (res int i = 0; i <= n; i += 4){
A[i] = f[i + l]; A[i + 1] = f[i + l + 1];
A[i + 2] = f[i + l + 2]; A[i + 3] = f[i + l + 3];
}
n = r - l - 1;
for (res int i = 0; i <= n; i += 4){
B[i] = fac[i + 1]; B[i + 1] = fac[i + 2];
B[i + 2] = fac[i + 3]; B[i + 3] = fac[i + 4];
}
m = mid - (l << 1) + r - 1; n = 1;
while (n <= m) n <<= 1,L++;
for (res int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
for (res int i = mid - l + 1; i < n; i += 4){
A[i] = A[i + 1] = A[i + 2] = A[i + 3] = 0;
}
for (res int i = r - l + 1; i < n; i += 4){
B[i] = B[i + 1] = B[i + 2] = B[i + 3] = 0;
}
NTT(A,n,1); NTT(B,n,1);
for (res int i = 0; i < n; i += 4){
A[i] = 1ll * A[i] * B[i] % P;
A[i + 1] = 1ll * A[i + 1] * B[i + 1] % P;
A[i + 2] = 1ll * A[i + 2] * B[i + 2] % P;
A[i + 3] = 1ll * A[i + 3] * B[i + 3] % P;
}
NTT(A,n,-1);
for (res int i = mid - l; i <= r - l - 1; i++)
f[i + l + 1] = (f[i + l + 1] + A[i]) % P;
solve(mid + 1,r);
}
void init(){
fac[0] = 1;
for (res int i = 1; i <= N; i++) fac[i] = 1ll * fac[i - 1] * i % P;
fv[N] = qpow(fac[N],P - 2); fv[0] = 1;
for (res int i = N - 1; i; i--)
fv[i] = 1ll * fv[i + 1] * (i + 1) % P;
for (res int i = 1; i < maxn; i <<= 1)
w[i] = qpow(G,(P - 1) / (i << 1));
f[0] = 1;
solve(1,N);
REP(i,N) f[i] = (f[i] + P) % P;
//REP(i,11) printf("%d ",f[i]); puts("");
}
int n,m,scc[maxn],vis[maxn];
int main(){
init();
int T = read();
while (T--){
n = read(); m = read(); int ans = 1,x;
REP(i,m) vis[i] = false;
REP(i,m){
x = read();
REP(j,x) scc[read()] = i;
ans = 1ll * ans * f[x] % P;
}
int flag = true;
for (res int i = 1; i <= n; i++){
if (i > 1 && scc[i] != scc[i - 1] && vis[scc[i]]){
flag = false; break;
}
vis[scc[i]] = true;
}
flag ? printf("%d\n",ans) : puts("0");
}
return 0;
}

ZOJ3874 Permutation Graph 【分治NTT】的更多相关文章

  1. ZOJ 3874 Permutation Graph 分治NTT

    Permutation Graph Time Limit: 2 Seconds      Memory Limit: 65536 KB Edward has a permutation {a1, a2 ...

  2. ZOJ 3874 Permutation Graph (分治NTT优化DP)

    题面:vjudge传送门 ZOJ传送门 题目大意:给你一个排列,如果两个数构成了逆序对,就在他们之间连一条无向边,这样很多数会构成一个联通块.现在给出联通块内点的编号,求所有可能的排列数 推来推去容易 ...

  3. ZOJ 3874 Permutation Graph ——分治 NTT

    发现每一块一定是按照一定的顺序的. 然后与标号无关,并且相同大小的对答案的影响相同. 然后列出递推式,上NTT+分治就可以了. 然后就可以与输入同阶处理答案了. #include <map> ...

  4. ZOJ3874 Permutation Graph

    Time Limit: 2 Seconds      Memory Limit: 65536 KB Edward has a permutation {a1, a2, … an}. He finds ...

  5. ZOJ3874 Permutation Graph(NTT&&cdq分治)

    最近在看几道整体二分还有cdq分治的东西,突然间想起前几个礼拜的ZOJ题,然后看了一下代码,经过了一些深思熟虑之后,发现自己终于看懂了,下面就用别人的代码来剖析一下整个解题的思路吧,具体的内容我再看看 ...

  6. HDU 5322 Hope (分治NTT优化DP)

    题面传送门 题目大意: 假设现在有一个排列,每个数和在它右面第一个比它大的数连一条无向边,会形成很多联通块. 定义一个联通块的权值为:联通块内元素数量的平方. 定义一个排列的权值为:每个联通块的权值之 ...

  7. [gdoi2018 day1]小学生图论题【分治NTT】

    正题 题目大意 一张随机的\(n\)个点的竞赛图,给出它的\(m\)条相互无交简单路径,求这张竞赛图的期望强联通分量个数. \(1\leq n,m\leq 10^5\) 解题思路 先考虑\(m=0\) ...

  8. #565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)

    题面 戳这里,题意简单易懂. 题解 首先我们发现,操作是可以不考虑顺序的,因为每次操作会加一个 \(1\) ,每次进位会减少一个 \(1\) ,我们就可以考虑最后 \(1\) 的个数(也就是最后的和) ...

  9. LOJ2541 PKUWC2018猎人杀(概率期望+容斥原理+生成函数+分治NTT)

    考虑容斥,枚举一个子集S在1号猎人之后死.显然这个概率是w1/(Σwi+w1) (i∈S).于是我们统计出各种子集和的系数即可,造出一堆形如(-xwi+1)的生成函数,分治NTT卷起来就可以了. #i ...

随机推荐

  1. mysql表的核心元数据

    索引的 mysql> show indexes from recordsInRangeTest; +--------------------+------------+------------- ...

  2. excell 导入 导出

    1.jar包 2.POIUtils工具类 package com.esstglobal.service.utils; import java.io.BufferedInputStream; impor ...

  3. hdu2149Public Sale(巴什博弈)

    Public Sale Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  4. Qt-QPalette-调色板学习

    已经很久没有更新博客了,一是因为换了公司,完全是断网开发了,没有时间来写博客,最主要的就是温水煮青蛙,自己在舒适的环境中越来越懒了,最近打算强制自己更新一波.不知道能坚持多久.由于目前没有具体的Qt项 ...

  5. MySQL☞关联查询

    关联查询:所需要的数据来源于多张表,通过表的连接查询(关联查询)来查询多张表中的数据 格式: select 别名1 . */列名 , 别名2 . */列名 from 表名1  别名1 , 表名2  别 ...

  6. Linux命令应用大词典-第35章 终端

    35.1 tty:显示当前连接到当前标准输入的终端设备文件名 35.2 consoletype:显示连接到标准输入的控制台类型 35.3 fgconsole:显示活动的虚拟终端数量 35.4 ming ...

  7. leetcode-电话号码的字母组合

    电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:"23" ...

  8. ubuntu ssh配置

    Secure Shell (SSH) is a cryptographic network protocol for operating network services securely over ...

  9. hibernate 异常a different object with the same identifier value was already associated with the session

    在使用hibernate的时候发现了一个问题,记录一下解决方案. 前提开启了事务和事务间并无commit,进行两次save,第二次的时候爆出下面的异常a different object with t ...

  10. SpringCloud IDEA 教学 (二) Eureka Service

    写在开头 本篇继续介绍基于Eureka的SpringCloud微服务搭建,回顾一下搭建过程, 第一步:建立一个服务注册中心: 第二步:建立微服务并注入到注册中心: 第三步:建立client端来访问微服 ...