zoukankan      html  css  js  c++  java
  • luogu P4566 [CTSC2018]青蕈领主

    luogu

    冷静分析这题有没有什么奇怪的性质

    小绿觉得被别的“连续”区间包含住的“连续”区间不够优秀

    这里不妨考虑“连续”区间的包含关系.对于两个有交的“连续”区间,如果没有包含关系就是不合法的,因为“连续”区间中所有数在值域上是连续的一段,那把这两个“连续”区间的值域段拿出来,这两段一定有交(因为在原序列上就有交,在值域上同样有).所以如果把靠后的“连续”区间的左端点延伸到靠前的“连续”区间的左端点,新的区间值域等于之前两个值域段的并,它也是连续的,所以原靠后区间就不是极长的“连续”区间

    那么对于一个排列,去掉最后一个元素后,剩下部分可以划分成若干极长“连续”区间,然后对于每个“连续”区间递归下去也可以得到类似结果,所以对于一个极长“连续”区间,我们从它的右端点向最后一个元素后,剩下的极长“连续”区间右端点连边,然后递归,就可以得到一个树形结构.现在要利用这个树形结构算答案,dfs整棵树,对于当前节点,因为要满足不存在 长度(>1)的不是整个区间的 “连续”区间,所以把不能存在一些相邻区间满足值域连续;又因为它的每个儿子节点代表的极长“连续”区间都是值域上连续的一段,所以可以把每个区间缩成一个数,这时加上最后一个位置,原问题可以就对应到一个长度为(i)的区间,满足不存在 长度(>1)的不是整个区间的 “连续”区间,记长度为(i)的这样排列数为(f_i),这个点就可以给答案乘上(f_{|son(x)|+1}(son(x))(x)儿子集合())

    现在考虑求(f_i).如果我们枚举所有长度为(i)的排列,那么这个排列去掉最后一位后,前面会划分成若干极长“连续”区间,我们要的是前面极长“连续”区间长度均为1的,等价于前面被划分成恰好(i-1)段.所以可以用总方案减掉前面划分段数更小的方案得到(f_i),设(g_{i,j})为长度为(i),且划分成(j)段,每段为一个排列的方案数(每段的排列代表一个值域连续的段).求不合法方案的时候同样可以把每一段缩成一个数,因为要满足一些相邻段不可以为“连续”区间,所以有(f_i=i!-sum_{j=1}^{i-2} g_{i-1,j}f_{j+1})

    考虑更优秀的做法,直接从(f)入手.为了方便,我们在原排列(p)的逆排列(p^{-1})上考虑,那么原来的“连续”区间可以唯一对应逆排列的“连续”区间,原问题可以改为求满足不存在不包括最大值的极长“连续”区间的排列个数.对于长度为(i)的合法排列,我们考虑删掉里面的1,然后把前后拼起来得到长度为(i-1)的序列列

    • 如果新排列还是合法的,那么一定满足12不相邻,这样的排列数为((i-2)f_{i-1})

    • 如果新排列不是合法的,那么只会有一个不包括最大值的极长“连续”区间,我们枚举其长度(l(l>1)),方案数的话,对于这个长度(i-1)的排列同样可以把这个长度(l)区间缩成一个数,对应一个长度(i-l)合法排列;然后对于这个段,先考虑其值域([x,x+l-1]),需要满足(x>2&&x+l-1<i),前者因为如果这个段中有2,加上1后还是连续的不合法段,后者是因为它不包括最大值,所以(x)取值有(i-l-2)种,然后考虑这个段的数相对顺序,由于加入1后这个段没有包含1的“连续”区间,所以可以把1认为是段内最大值,对应一个长度(l+1)合法排列.这部分贡献为((i-2)f_{i-1}+sum_{l=2}^{i-2}(i-l-2)f_{i-l}f_{l+1})

    然后分治FFT优化(f_i=(i-2)f_{i-1}+(i-2)f_{i-1}+sum_{l=2}^{i-3}(i-l-2)f_{i-l}f_{l+1})即可

    #include<bits/stdc++.h>
    #define LL long long
    #define db double
    
    using namespace std;
    const int N=50000+10,M=(1<<17)+10,mod=998244353;
    int rd()
    {
    	int x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    	return x*w;
    }
    int to[N],nt[N],hd[N],tot=1;
    void adde(int x,int y){++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;}
    int n,T,sz[N],a[N],g[N],ans,fac[N],st[N],tp;
    void dfs(int x)
    {
    	sz[x]=1;
    	for(int i=hd[x];i;i=nt[i])
    	{
    		int y=to[i];
    		dfs(y),++sz[x];
    	}
    	ans=1ll*ans*g[sz[x]]%mod;
    }
    int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;}return an;}
    int ginv(int a){return fpow(a,mod-2);}
    int W[16],iW[16],rdr[M];
    void ntt(int *a,int n,bool op)
    {
    	int l=0,y;
    	while(1<<l<n) ++l;
    	for(int i=0;i<n;++i)
    	{
    		rdr[i]=(rdr[i>>1]>>1)|((i&1)<<(l-1));
    		if(i<rdr[i]) swap(a[i],a[rdr[i]]);
    	}
    	for(int i=1,p=0;i<n;i<<=1,++p)
    	{
    		int ww=op?W[p]:iW[p];
    		for(int j=0;j<n;j+=i<<1)
    			for(int k=0,w=1;k<i;++k,w=1ll*w*ww%mod)
    				y=1ll*a[j+k+i]*w%mod,a[j+k+i]=(a[j+k]-y+mod)%mod,a[j+k]=(a[j+k]+y)%mod;
    	}
    	if(!op) for(int i=0,w=ginv(n);i<n;++i) a[i]=1ll*a[i]*w%mod;
    }
    int aa[M],bb[M];
    void sov(int l,int r)
    {
    	if(l==r)
    	{
    		if(l>2) g[l]=(1ll*(l-2)*g[l-1]+g[l])%mod;
    		return;
    	}
    	int mid=(l+r)>>1;
    	sov(l,mid);
    	int l1=l>1?r+1-l:mid-l+1,len=1;
    	while(len<=l1+l1) len<<=1;
    	for(int i=max(l,3);i<=mid;++i) aa[i-l]=g[i];
    	for(int i=3;i<=l1;++i) bb[i]=1ll*g[i]*(i-2)%mod;
    	ntt(aa,len,1),ntt(bb,len,1);
    	for(int i=0;i<len;++i) aa[i]=1ll*aa[i]*bb[i]%mod;
    	ntt(aa,len,0);
    	for(int i=mid+1;i<=r;++i) g[i]=(g[i]+aa[i-l+1])%mod;
    	memset(aa,0,sizeof(int)*len),memset(bb,0,sizeof(int)*len);
    	if(l>1)
    	{
    		for(int i=max(l,3);i<=mid;++i) aa[i-l]=1ll*g[i]*(i-2)%mod;
    		for(int i=3;i<=l1;++i) bb[i]=g[i];
    		ntt(aa,len,1),ntt(bb,len,1);
    		for(int i=0;i<len;++i) aa[i]=1ll*aa[i]*bb[i]%mod;
    		ntt(aa,len,0);
    		for(int i=mid+1;i<=r;++i) g[i]=(g[i]+aa[i-l+1])%mod;
    		memset(aa,0,sizeof(int)*len),memset(bb,0,sizeof(int)*len);
    	}
    	sov(mid+1,r);
    }
    
    int main()
    {
    	for(int i=1,p=0;p<16;i<<=1,++p)
    		W[p]=fpow(3,(mod-1)/(i<<1)),iW[p]=ginv(W[p]);
    	T=rd(),n=rd();
    	fac[0]=1;
    	g[1]=1,g[2]=2;
    	sov(1,n);
        /*for(int i=3;i<=n;++i)
    	{
    		LL na=(LL)(i-2)*g[i-1];
    		for(int j=2;j<=i-3;++j)
    			na+=(LL)(i-j-2)*g[i-j]*g[j+1];
    		g[i]=na%mod;
    	}*/
    	while(T--)
    	{
    		for(int i=1;i<=n;++i) a[i]=rd();
    		bool ok=1;
    		memset(hd,0,sizeof(int)*(n+1)),tot=1;
    		ans=1,tp=0;
    		for(int i=n;i;--i)
    		{
    			while(tp&&st[tp]-a[st[tp]]+1>i) --tp;
    			if(tp) adde(st[tp],i),ok&=st[tp]-a[st[tp]]+1<=i-a[i]+1;
    			else if(i<n) ok=0;
    			st[++tp]=i;
    		}
    		if(!ok){puts("0");continue;}
    		dfs(n),printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Web开发利器Webstorm导入多个文件夹或者项目
    js react 全选和反选
    nginx的配置文件 【nginx.conf】
    nginx 服务器重启命令,关闭
    Nginx反向代理新篇-使用location对多个URL做反向代理
    Windows下Nginx的安装与配置
    es6 递归 tree
    自定义table样式
    数据库(7)
    数据库(6)
  • 原文地址:https://www.cnblogs.com/smyjr/p/13033483.html
Copyright © 2011-2022 走看看