题意:略

我们发现对于 $n$ 棵树,有用的是所有树的相对大小关系.

而随机生成 $[0,1]$ 之间的实数的相对大小关系可以等价于随机生成一个排列的相对大小关系(我们可以认为这个小数是无限长的,一定能比较出两者大小)

此问题就转化为:对于 $n!$ 种排列,权值综合为多少 $?$

我们定义一些互相可以到达的树为一个连通块,然后我们发现如果一个排列中 $l$ 能连向 $r$,那么在该排列中 $[l,r]$ 一定相互联通.

所以,对于一个排列 $P$ 来说,假设有 $x$ 个连通块,那么这 $x$ 个连通块一定是从头开始值域依次递减的.

例如:$[8,10],[5,7],[3,4],[1,2]$

令 $f[n]$ 表示由 $1$ ~ $n$ 这 $n$ 个元素构成的连通块大小为 $n$ 的排列数.(即 $1$ 到 $n$ 全部联通)

那么 $Ans[n]=\sum_{i=0}^{n-1}Ans[i]\times f[n-i] \times (n-i)$.

构造生成函数 $ANS(x)=\sum_{i=0}^{\infty} Ans[i]\times x^i$,$M(x)=\sum_{i=1}^{\infty} i\times f[i]\times x^i$

$\Rightarrow ANS(x)-1=ANS(x)M(x)$

$\Rightarrow ANS(x)=\frac{1}{1-M(x)}$

正着求 $f[n]$ 很困难,不妨容斥一下:$f[n]=n!-\sum_{i=1}^{n-1}f[i]\times (n-i)!$,即枚举序列开头的连通块,然后由于值域递减,所以后面那 $(n-i)!$ 种排列都不能与前面形成一个连通块.

再做一个多项式求逆就求出 f 了,$\Rightarrow F(x)=\frac{FAC(x)-1}{FAC(x)}$

#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>
#define ll long long
#define ull unsigned long long
using namespace std;
namespace IO
{
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd()
{
int x=0; char s=nc();
while(s<'0') s=nc();
while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
return x;
}
void print(int x) {if(x>=10) print(x/10);putchar(x%10+'0');}
void setIO(string s)
{
string in=s+".in";
string out=s+".out";
freopen(in.c_str(),"r",stdin);
// freopen(out.c_str(),"w",stdout);
}
};
const int G=3;
const int N=2000005;
const int mod=998244353;
int A[N],B[N],w[2][N],mem[N*100],*ptr=mem,tmpa[N],tmpb[N],aa[N],bb[N];
inline int qpow(int x,int y)
{
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod;
return tmp;
}
inline int INV(int a) { return qpow(a,mod-2); }
inline void ntt_init(int len)
{
int i,j,k,mid,x,y;
w[1][0]=w[0][0]=1,x=qpow(G,(mod-1)/len),y=qpow(x,mod-2);
for (i=1;i<len;++i) w[0][i]=(ll)w[0][i-1]*x%mod,w[1][i]=(ll)w[1][i-1]*y%mod;
}
void NTT(int *a,int len,int flag)
{
int i,j,k,mid,x,y;
for(i=k=0;i<len;++i)
{
if(i>k) swap(a[i],a[k]);
for(j=len>>1;(k^=j)<j;j>>=1);
}
for(mid=1;mid<len;mid<<=1)
for(i=0;i<len;i+=mid<<1)
for(j=0;j<mid;++j)
{
x=a[i+j], y=(ll)w[flag==-1][len/(mid<<1)*j]*a[i+j+mid]%mod;
a[i+j]=(x+y)%mod;
a[i+j+mid]=(x-y+mod)%mod;
}
if(flag==-1)
{
int rev=INV(len);
for(i=0;i<len;++i) a[i]=(ll)a[i]*rev%mod;
}
}
inline void getinv(int *a,int *b,int len,int la)
{
if(len==1) { b[0]=INV(a[0]); return; }
getinv(a,b,len>>1,la);
int l=len<<1,i;
memset(A,0,l*sizeof(A[0]));
memset(B,0,l*sizeof(A[0]));
memcpy(A,a,min(la,len)*sizeof(a[0]));
memcpy(B,b,len*sizeof(b[0]));
ntt_init(l);
NTT(A,l,1),NTT(B,l,1);
for(i=0;i<l;++i) A[i]=((ll)2-(ll)A[i]*B[i]%mod+mod)*B[i]%mod;
NTT(A,l,-1);
memcpy(b,A,len<<2);
}
void get_dao(int *a,int *b,int len)
{
for(int i=1;i<len;++i) b[i-1]=(ll)i*a[i]%mod;
b[len-1]=0;
}
void get_jifen(int *a,int *b,int len)
{
for(int i=1;i<len;++i) b[i]=(ll)INV(i)*a[i-1]%mod;
b[0]=0;
}
void get_ln(int *a,int *b,int len,int la)
{
int l=len<<1,i;
memset(tmpa,0,l<<2);
memset(tmpb,0,l<<2);
get_dao(a,tmpa,min(len,la));
getinv(a,tmpb,len,la);
ntt_init(l);
NTT(tmpa,l,1),NTT(tmpb,l,1);
for(i=0;i<l;++i) tmpa[i]=(ll)tmpa[i]*tmpb[i]%mod;
NTT(tmpa,l,-1);
get_jifen(tmpa,b,len);
}
void get_exp(int *a,int *b,int len,int la)
{
if(len==1) { b[0]=1; return; }
int l=len<<1,i;
get_exp(a,b,len>>1,la);
for(i=0;i<l;++i) aa[i]=bb[i]=0;
for(i=0;i<(len>>1);++i) aa[i]=b[i];
get_ln(b,bb,len,len>>1);
for(i=0;i<len;++i) bb[i]=(ll)(mod-bb[i]+(i>=la?0:a[i]))%mod;
bb[0]=(bb[0]+1)%mod;
ntt_init(l);
NTT(aa,l,1),NTT(bb,l,1);
for(i=0;i<l;++i) aa[i]=(ll)aa[i]*bb[i]%mod;
NTT(aa,l,-1);
for(i=0;i<len;++i) b[i]=aa[i];
}
struct poly
{
int len,*a;
poly(){}
poly(int l) {len=l,a=ptr,ptr+=l; }
inline void rev() { reverse(a,a+len); }
inline void fix(int l) {len=l,a=ptr,ptr+=l;}
inline void get_mod(int l) { for(int i=l;i<len;++i) a[i]=0; len=l; }
inline poly dao()
{
poly re(len-1);
for(int i=1;i<len;++i) re.a[i-1]=(ll)i*a[i]%mod;
return re;
}
inline poly jifen()
{
poly c;
c.fix(len+1);
c.a[0]=0;
for(int i=1;i<=len;++i) c.a[i]=(ll)a[i-1]*INV(i)%mod;
return c;
}
inline poly Inv(int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim);
getinv(a,b.a,lim,len);
b.get_mod(l);
return b;
}
inline poly ln(int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim);
get_ln(a,b.a,lim,len);
return b;
}
inline poly exp(int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim);
get_exp(a,b.a,lim,len);
return b;
}
inline poly q_pow(int k,int l)
{
int lim=1;
while(lim<=l) lim<<=1;
poly b(lim),c(lim);
get_ln(a,b.a,lim,len);
for(int i=0;i<b.len;++i) b.a[i]=(ll)b.a[i]*k%mod;
get_exp(b.a,c.a,lim,b.len);
c.get_mod(l);
return c;
}
inline poly operator*(const poly &b) const
{
poly c(len+b.len-1);
if(c.len<=500)
{
for(int i=0;i<len;++i)
if(a[i]) for(int j=0;j<b.len;++j) c.a[i+j]=(c.a[i+j]+(ll)(a[i])*b.a[j])%mod;
return c;
}
int n=1;
while(n<(len+b.len)) n<<=1;
memset(A,0,n<<2);
memset(B,0,n<<2);
memcpy(A,a,len<<2);
memcpy(B,b.a,b.len<<2);
ntt_init(n);
NTT(A,n,1), NTT(B,n,1);
for(int i=0;i<n;++i) A[i]=(ll)A[i]*B[i]%mod;
NTT(A,n,-1);
memcpy(c.a,A,c.len<<2);
return c;
}
poly operator+(const poly &b) const
{
poly c(max(len,b.len));
for(int i=0;i<c.len;++i) c.a[i]=((i<len?a[i]:0)+(i<b.len?b.a[i]:0))%mod;
return c;
}
poly operator-(const poly &b) const
{
poly c(len);
for(int i=0;i<len;++i)
{
if(i>=b.len) c.a[i]=a[i];
else c.a[i]=(a[i]-b.a[i]+mod)%mod;
}
return c;
}
poly operator/(poly u)
{
int n=len,m=u.len,l=1;
while(l<(n-m+1)) l<<=1;
rev(),u.rev();
poly v=u.Inv(l);
v.get_mod(n-m+1);
poly re=(*this)*v;
rev(),u.rev();
re.get_mod(n-m+1);
re.rev();
return re;
}
poly operator%(poly u)
{
poly re=(*this)-u*(*this/u);
re.get_mod(u.len-1);
return re;
}
}Fac,F,tmp,Ans;
#define MAX 500001
int fac[N],inv[N],n;
void init()
{
int i,j;
fac[0]=inv[0]=1;
for(i=1;i<MAX;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=INV(fac[i]);
}
int main()
{
// IO::setIO("input");
int i,j;
scanf("%d",&n),init();
Fac.fix(1+n),tmp.fix(1+n),Fac.a[0]=0;
for(i=1;i<=n;++i) tmp.a[i]=Fac.a[i]=fac[i]; tmp.a[0]=1;
tmp=tmp.Inv(1+n); F=Fac*tmp; F.get_mod(1+n),F.a[0]=1;
for(i=1;i<=n;++i) F.a[i]=(ll)(-(ll)i*F.a[i]%mod+mod)%mod;
Ans=F.Inv(1+n);
printf("%d\n",Ans.a[n]);
return 0;
}

  

LOJ #6402. yww 与校门外的树 多项式求逆的更多相关文章

  1. 【LOJ#10115,tyvj1473】校门外的树(第3次升级)

    PS:思路来源于Clove_unique的博客,在此万分感谢 这道题可以用树状数组轻松过,然而...树状数组不太熟悉,还是用线段树比较好(虽然代码比较长) [思路分析] [一开始的思路] 最开始的错误 ...

  2. P1047 校门外的树

    P1047 校门外的树 题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0 ...

  3. Vijos1448校门外的树 题解

    Vijos1448校门外的树 题解 描述: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现 ...

  4. OpenJudge计算概论-校门外的树

    /*======================================================================== 校门外的树 总时间限制: 1000ms 内存限制: ...

  5. [swustoj 764] 校门外的树 Plus Plus

    校门外的树 Plus Plus(0764) 问题描述 西南某科技大学的校门外长度为 L 的公路上有一排树,每两棵相邻的树之间的间隔都是 1 米.我们可以把马路看成一个数轴,马路的一端在数轴 1 的位置 ...

  6. 校门外的树 - Grids2808

    校门外的树 问题描述: 某校大门外长度为 L 的马路上有一排树,每两棵相邻的树之间的间隔都是1 米.我们 可以把马路看成一个数轴,马路的一端在数轴0 的位置,另一端在L 的位置:数轴上的每 个整数点, ...

  7. 校门外的树 OpenJudge 1.6.06

    06:校门外的树 总时间限制:  1000ms 内存限制:  65536kB 描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0 ...

  8. 【解题报告】VijosP1448校门外的树(困难版)

    原题: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的--如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r ...

  9. Vijos P1103 校门外的树【线段树,模拟】

    校门外的树 描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……, ...

随机推荐

  1. python库之matplotlib学习---关于坐标轴

    首先定·定义x, y创建一个figure import numpy as np import matplotlib.pyplot as plt x = np.linspace(-1, 1, 10) y ...

  2. Dubbo 服务 IP 注册错误踩坑经历

    个人博客地址 studyidea.cn,点击查看更多原创文章 踩坑 公司最近新建一个机房,需要将现有系统同步部署到新机房,部署完成之后,两地机房同时对提供服务.系统架构如下图: 这个系统当前对外采用 ...

  3. 11g与12c启动,关闭RAC

    oracle11g 关闭,启动顺序 1.关闭数据库(oracle)srvctl stop database -d rac 2.关闭集群(root)crsctl stop cluster -all 3. ...

  4. 【题解】[P1045] 麦森数

    题目 题目描述 形如2^P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^P-1 不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=30213 ...

  5. 一起了解 .Net Foundation 项目 No.2

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. ASP.NET MVC, ...

  6. mysql ---- Host '' is not allowed to connect to this MySQL server

    mysql>use mysql mysql>update user set host= '%' where user = 'root'; 此时如果提示报错,不用管,继续往下走 select ...

  7. 持续集成:jenkins集合

    持续集成:jenkins集合 jenkins(一):   持续集成和Jenkins简介 jenkins(二):   Jenkins的安装 jenkins(三):   Jenkins的应用场景和job ...

  8. pos 访问超时 windows连接超时 497 天后未关闭 TIME_WAIT

    问题描述: nginx连接后台tomcat程序 一直报错 nginx的error日志如下 // :: [error] #: *: A connection attempt failed because ...

  9. lua 打印一个table的实现

    print("-------------Test-----------------") local tb = {} function printProperties(t, csp) ...

  10. 记录KVM虚拟机常用操作管理命令

    环境说明 centos7中的KVM NAT方式是kvm安装后的默认方式.它支持主机与虚拟机的互访,同时也支持虚拟机访问互联网,但不支持外界访问虚拟机. 检查当前的网络设置 # virsh net-li ...