[Contest20180426] The tree outside the school gate

$\newcommand{\align}[1]{\begin{align*}#1\end{align*}}$ Meaning: For a permutation $p_{1\cdots n}$ constructs a graph, if $i\ lt j$ and $p_i\lt p_j$, even the bidirectional edge $(i,j)$, the weight of this permutation is the product of the sizes of all connected blocks, and the sum of the weights of all $n!$ permutations

Considering DP, let $f_n$ represent the number of connected solutions (a graph composed of permutations of length $n$), then we can use $n!$ to subtract the number of disconnected solutions, and consider the illegal solutions as the first The size of connected blocks $i$ is classified, then the number of $ni$ can be randomly arranged, so $\align{f_n=n!-\sum\limits_{i=1}^{n-1}(ni)! f_i}$

Let the answer be $g_n$, enumerating the size $i$ of the last connected block, we get the shift $\align{g_n=\sum\limits_{i=1}^nif_ig_{ni}}$

Doing this is $O(n^2)$, considering optimization

First convert the recursion of $f$, $\align{2n!=[n=0]+\sum\limits_{i=0}^n(ni)!f_i}$

设$\align{A(x)=\sum\limits_ii!x^i,B(x)=\sum\limits_if_ix^i}$,则$2A(x)=A(x)B(x)+1$,即$B(x)=\dfrac{2A(x)-1}{A(x)}$

Direct polynomial inversion can calculate $B(x)$, set $\align{C(x)=\sum\limits_iif_ix^i}$, now consider calculating the answer, enumerate the number of connected blocks in the answer $k$, The answer is $\align{[x^n]\sum\limits_{i=1}^\infty C^k(x)=[x^n]\left(\dfrac1{1-C(x)}-1 \right)}$, calculate $C(x)$ and then inverse it

But the cancer yww put it out to $n\leq5\times10^5$, if it is written in this way, it will drop T, so let's come to Kaka often==

First notice that $C(x)$ is actually an extra $i$ for each coefficient of $B(x)$, so $C(x)=xB'(x)$, and then use $B(x) =\dfrac{2A(x)-1}{A(x)}$, we get $\dfrac1{1-C(x)}=\dfrac{A^2(x)}{A^2(x) -xA'(x)}$, optimized to only use two FFTs and one polynomial inversion, which can be passed

We can continue to optimize, we need to find a way to quickly calculate $\align{h_n=[x^n]A^2(x)=\sum\limits_{i=0}^ni!(ni)!}$, in The recursive formula $h_n=n!+\dfrac{n+1}2h_{n-1}$ can be found on OEIS , but I haven’t found a proof to see if there is a chance to fill the pit in the future, so I can just do first degree polynomial inversion

#include<stdio.h>
#include<string.h>
const int mod=998244353,maxn=1048576;
typedef long long ll;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
int pow(int a,int b){
	int s=1;
	while(b){
		if(b&1)s=mul(s,a);
		a=mul(a,a);
		b>>=1;
	}
	return s;
}
int rev[maxn],N,iN;
void pre(int n){
	int i,k;
	for(N=1,k=0;N<n;N<<=1)k++;
	for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
	iN=pow(N,mod-2);
}
void swap(int&a,int&b){a^=b^=a^=b;}
void ntt(int*a,int on){
	int i,j,k,t,w,wn;
	for(i=0;i<N;i++){
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(i=2;i<=N;i<<=1){
		wn=pow(3,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i));
		for(j=0;j<N;j+=i){
			w=1;
			for(k=0;k<i>>1;k++){
				t=mul(w,a[i/2+j+k]);
				a [i/2+j+k] = de (a [j+k], t);
				a[j+k]=ad(a[j+k],t);
				w=mul(w,wn);
			}
		}
	}
	if(on==-1){
		for(i=0;i<N;i++)a[i]=mul(a[i],iN);
	}
}
int t[maxn];
void getinv(int*a,int*b,int n){
	if(n==1){
		b[0]=pow(a[0],mod-2);
		return;
	}
	int i;
	getinv(a,b,n>>1);
	pre(n<<1);
	memset(t,0,N<<2);
	memcpy(t,a,n<<2);
	ntt(t,1);
	ntt(b,1);
	for(i=0;i<N;i++)b[i]=mul(b[i],2-mul(b[i],t[i]));
	ntt(b,-1);
	for(i=n;i<N;i++)b[i]=0;
}
int a[maxn],b[maxn],c[maxn];
int main(){
	int n,k,i,years;
	scanf("%d",&n);
	for(k=1;k<=n;k<<=1);
	a[0]=1;
	for(i=1;i<=n;i++){
		a[i]=mul(i,a[i-1]);
		b[i]=mul(i,a[i]);
	}
	pre(k<<1);
	ntt(a,1);
	for(i=0;i<N;i++)a[i]=mul(a[i],a[i]);
	ntt(a,-1);
	for(i=0;i<=n;i++)b[i]=de(a[i],b[i]);
	getinv(b,c,k);
	years=0;
	for(i=0;i<=n;i++)ans=ad(ans,mul(a[i],c[n-i]));
	printf("%d",ad(ans,mod));
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325011468&siteId=291194637