uoj#401. 【CTSC2018】青蕈领主(分治FFT)
话说分治\(FFT\)是个啥子啊……还有题目里那字好像念(蕈xùn)
首先考虑无解的情况:区间相交或者\(L_n\neq n\)
这两个都可以感性理解一下
所以区间之间只会有包含关系,我们把每个小区间向它右边的第一个包含它的大区间连边,那么会构成一个树形结构
对于一个大区间来说,那些作为它儿子的小区间每一个都是连续的,并且互不相交,假设它有\(sz\)个儿子,把每一个儿子都缩成一个点,那么就是需要一个排列满足\(L\)分别为\(1,1,1,...,sz+1\),其中第\(sz+1\)个是大区间自己,也就是除了最后一个节点之外不存在任何一个大于\(1\)的连续子区间,我们称其为合法排列
设\(f_i\)为长度为\(i+1\)的除整个区间外不存在连续最长子区间的排列个数,那么答案就是\(\prod f(sz)\)
顺便说一句\(sz\)可以用单调栈\(O(n)\)求出
考虑\(f\)应该如何计算,有$$f_i=(i-1)f_{i-1}+\sum_{j=2}^{i-2}(j-1)f_jf_{i-j}$$
这个怎么解释嘞
我们设\(b_{a_i}=i\),那么原数列中连续区间在新的数列中也还是连续区间,且在原序列中包含最后一个节点的区间就是新数列中包含最大值的区间
那么我们可以稍微改一下\(f_i\)的定义,为除包含最大值外不存在连续最长子区间的排列个数,这个定义是和之前等价的
然后考虑上面的递推式
即在一个长度为\(i\)的排列中插入一个数来得到\(i+1\)
1.原排列本来就合法,那么只要插入的\(i+1\)不和\(i\)相邻即可,有\(i-1\)个位置可放
2.原排列不合法,插入的\(i+1\)使其合法。这种时候原排列一定只有一个不经过最大值的连续最长子区间,那么枚举这个子区间的长度\(j\in [2,i-2]\),插入这个最大值会使这个区间被分为两部分,这两部分和最大值形成的整个区间是一个合法的排列,长度为\(j+1\),方案为\(f_j\),这一段区间值域为\([x,x+j-1]\),那么\(x\)的选择方案为\(n-j-1\)种。再把这个区间视为一个整体,这样整个排列共有\(i-j+1\)个数字,方案数为\(f_{i-j}\)
于是递推过程就是$$f_i=(i-1)f_{i-1}+\sum_{j=2}^{i-2}(i-j-1)f_jf_{i-j}$$
\]
这个可以用分治\(FFT\)优化
然后说一下好了……这个分治\(FFT\)的过程比较神仙……
因为我们分治的时候使用\([l,mid]\)卷上\([1,r-l]\),然后加到\([mid+1,r]\)上,但问题是\(r-l\)之类的可能还没求出来……
于是我们让\([l,mid]\)卷上\([1,\min(r-l,l-1)]\),这样的话卷的东西都是我们已经求好了的
然后本来是要\([l,mid]\)和\([1,\min(r-l,l-1)]\),\([1,\min(r-l,l-1)]\)和\([l,mid]\)分别卷的,不过因为\((j-1)f_jf_{j-i}+(i-j-1)f_{j-i}f_j=(i-2)f_jf_{i-j}\),所以可以卷一次再乘上\(i-2\)
然后没啥然后了……
//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
inline int min(const R int &x,const R int &y){return x<y?x:y;}
inline int max(const R int &x,const R int &y){return x>y?x:y;}
inline void swap(R int &x,R int &y){x^=y^=x^=y;}
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=2e5+5,P=998244353,Gi=332748118;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
int r[N],f[N],st[N],A[N],B[N],a[N],O[N];
int lim,l,n,m,res,top,sz;bool flag;
void NTT(int *A,int ty){
fp(i,0,lim-1)if(i<r[i])swap(A[i],A[r[i]]);
for(R int mid=1;mid<lim;mid<<=1){
int I=(mid<<1),Wn=ksm(ty==1?3:Gi,(P-1)/I);O[0]=1;
fp(i,1,mid-1)O[i]=mul(O[i-1],Wn);
for(R int j=0;j<lim;j+=I)fp(k,0,mid-1){
int x=A[j+k],y=mul(O[k],A[j+k+mid]);
A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
}
}if(ty==-1)for(R int i=0,inv=ksm(lim,P-2);i<lim;++i)A[i]=mul(A[i],inv);
}
void Mul(int *A,int *B,int n,int m){
lim=1,l=0;while(lim<=n+m)lim<<=1,++l;
fp(i,0,lim-1)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
fp(i,n,lim-1)A[i]=0;fp(i,m,lim-1)B[i]=0;
NTT(A,1),NTT(B,1);
fp(i,0,lim-1)A[i]=mul(A[i],B[i]);
NTT(A,-1);
}
void CDQ(int l,int r){
if(l==r)return f[l]=add(f[l],mul(l-1,f[l-1])),void();
int mid=(l+r)>>1;CDQ(l,mid);
fp(i,l,mid)A[i-l]=mul(i-1,f[i]),B[i-l]=f[i];
Mul(A,B,mid-l+1,mid-l+1);
fp(i,max(l<<1,mid+1),r)f[i]=add(f[i],A[i-(l<<1)]);
if(l!=2){
int d=min(l-1,r-l);
fp(i,2,d)A[i-2]=f[i];
fp(i,l,mid)B[i-l]=f[i];
Mul(A,B,d-1,mid-l+1);
fp(i,max(l+2,mid+1),r)f[i]=add(f[i],mul(i-2,A[i-l-2]));
}CDQ(mid+1,r);
}
int main(){
// freopen("testdata.in","r",stdin);
int T=read();n=read();
f[0]=1,f[1]=2;
if(n>2)CDQ(2,n-1);
while(T--){
flag=true,res=1,top=0;
fp(i,1,n)a[i]=read();
if(a[n]!=n||a[1]!=1){puts("0");continue;}
fp(i,1,n){
sz=0;
while(top&&i-a[i]+1<=st[top]){
if(i-a[i]+1>st[top]-a[st[top]]+1){flag=false;break;}
++sz,--top;
}
if(!flag)break;
res=mul(res,f[sz]),st[++top]=i;
}
printf("%d\n",flag?res:0);
}
return 0;
}
uoj#401. 【CTSC2018】青蕈领主(分治FFT)的更多相关文章
- UOJ#401. 【CTSC2018】青蕈领主 分治,FFT
原文链接www.cnblogs.com/zhouzhendong/p/UOJ401.html 题解 首先,对于一个排列,它的连续段一定只有包含关系,没有相交关系. 我们可以据此得到一棵表示连续段的树. ...
- [CTSC2018]青蕈领主
[CTSC2018]青蕈领主 题解 首先,连续段要知道结论: 连续段要么不交,要么包含 所以是一棵树!每个位置的father是后面第一个包含它的 树形DP! 设dp[x],x为根的子树,(设管辖的区间 ...
- 并不对劲的bzoj5342:loj2554:uoj401:p4566: [Ctsc2018]青蕈领主
题目大意 \(T\)(\(T\leq100\))组询问 有\(1\)到\(n\)(\(n\leq50000\))这\(n\)个整数组成的一个排列 定义这个排列的一个子区间是"连续" ...
- Loj #2554. 「CTSC2018」青蕈领主
Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...
- LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT
题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...
- bzoj5342 CTSC2018 Day1T3 青蕈领主
首先显然的是,题中所给出的n个区间要么互相包含,要么相离,否则一定不合法. 然后我们可以对于直接包含的关系建出一棵树,于是现在的问题就是给n个节点分配权值,使其去掉最后一个点后不存在非平凡(长度大于1 ...
- 【UOJ#50】【UR #3】链式反应(分治FFT,动态规划)
[UOJ#50][UR #3]链式反应(分治FFT,动态规划) 题面 UOJ 题解 首先把题目意思捋一捋,大概就是有\(n\)个节点的一棵树,父亲的编号大于儿子. 满足一个点的儿子有\(2+c\)个, ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- BNUOJ 51279[组队活动 Large](cdq分治+FFT)
传送门 大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案.两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中 ...
随机推荐
- Nginx之解压编译安装-yellowcong
安装前准备 对于nginx编译安装需要先安装编译 的工具,然后再安装nginx依赖 yum -y install gcc gcc-c++ autoconf automake make yum -y i ...
- js中得~~是什么意思/JS按位非(~)运算符与~~运算符的理解分析
其实是一种利用符号进行的类型转换,转换成数字类型 ~~true == 1 ~~false == 0 ~~"" == 0 ~~[] == 0 ~~undefined ==0 ~~!u ...
- 加州小学grade1,学习计划
Visual vocabulary Grammar Spelling Maths Chapter 1 Patterns and Number SenseChapter 2Understanding A ...
- Redis- 内存数据库Redis之安装部署
内存数据库Redis之安装部署 Redis是一款非关系型,key-value存储的内存数据库,Redis数据库完全在内存中,使用磁盘仅用于持久性.Redis的速度非常快,每秒能执行约11万集合,每秒约 ...
- C++中两个类相互包含引用问题
在构造自己的类时,有可能会碰到两个类之间的相互引用问题,例如:定义了类A类B,A中使用了B定义的类型,B中也使用了A定义的类型 class A { int i; B b; } class B { in ...
- python 之gc(回收机制)--garbage collection(GC垃圾回收)
######################引用计数######################### 引用计数:python 当中一种用来解决垃圾回收的策略之一 char 1个字节(2**8) in ...
- 「P3385」【模板】负环(spfa
题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 ...
- bzoj 1369: Gem 树形dp
题目大意 给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数 唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小.N<=10000 题解 我们可以 ...
- 创建自己的YUM仓库
1. 首先,假定我们应用的名字叫helloworld(可以参考简单 RPM 包制作来创建两个版本helloworld安装RPM包,helloworld-1.0.0-1.el6.x86_64.rpm和h ...
- Set connectionId threw an exception.
今天调试一个WPF程序时,出现一个问题. 程序运行后抛出异常, "Set connectionId threw an exception. XXXXXXXXXX",原因是依赖的一个 ...