\(\mathcal{Description}\)

  Link.

  称排列 \(\{p_n\}\) 美妙,当且仅当 \((\forall i\in[1,n))(\max_{j\in[1,i]}\{p_i\}>\min_{j\in(i,n]}\{p_j\})\)。求长度为 \(n\) 的美妙排列个数。多测。

  \(n\le10^5\)。

\(\mathcal{Solution}\)

  讨论这道题的时候——打表,然后发现了 A003319!/xyx

  显然 \(f(0)=0,f(1)=1\),然后 A003319 给出了长度为 \(n\) 的美妙排列个数 \(f(n)\) 的递推式:

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

  先证明这个递推。等式相当于用所有方案 \(n!\) 减去了所有不美妙的序列方案并保证其不重复。考虑当求和的 \(i\) 等于某个数 \(k\) 时,构造序列:

\[\overbrace{p_1~~~~p_2~~~~\cdots~~~~p_k}^{\text{a permutation from 1 to k}}~~~~\overbrace{p_{k+1}~~~~p_{k+2}~~~~\cdots~~~~p_n}^{\text{a permutation from k+1 to n}}
\]

  其中,后一个排列由合法的 \(f(n-k)\) 整体 \(+k\) 形成,显然它是合法的。但当分隔点在 \(k\) 时,前缀最大为 \(k\),后缀最小为 \(k+1\),可见整个排列不合法。这样计算是不会算重的——非法排列仅会在分隔点在 \(k\) 处时被算一次,否则将任意一个数 \(t\in[1,k]\) 加入后面合法的排列,都会使排列不合法,不满足 \(f(n-k)\) 的定义。

  接下来着手计算。移项:

\[\sum_{i=0}^{n}i!f(n-i)=n!
\]

  那么 \(f\) 的 \(\text{OGF}\) 满足:

\[1+F(x)P(x)=P(x)
\]

  \(+1\) 是因为左式的 \(f_0\) 被定义为 \(0\),而 \(0!=1\),所以常数项 \(+1\)。最后移项得到 \(F(x)\) 的表达式:

\[F(x)=1-P^{-1}(x)
\]

  多项式求逆算出 \(F\) 即可。复杂度 \(\mathcal O(n\log n)-\mathcal O(1)\)。

\(\mathcal{Code}\)

#include <cmath>
#include <cstdio> const int MAXN = 1 << 18, MOD = 998244353;
int fac[MAXN + 5], F[MAXN + 5]; inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int sub ( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int mul ( long long a, const int b ) { return ( a *= b ) < MOD ? a : a % MOD; } inline int qkpow ( int a, int b, const int p = MOD ) {
int ret = 1;
for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
return ret;
} namespace Poly { const int G = 3; inline int adjust ( const int n ) {
int ret = 0;
for ( int l = 1; l < n; l <<= 1, ++ ret );
return ret;
} inline void NTT ( const int n, int* A, const int tp ) {
static int lstn = -1, rev[MAXN + 5] {};
if ( lstn ^ n ) {
int lgn = log ( n ) / log ( 2 ) + 0.5;
for ( int i = 0; i < n; ++ i ) rev[i] = ( rev[i >> 1] >> 1 ) | ( ( i & 1 ) << lgn >> 1 );
lstn = n;
}
for ( int i = 0; i < n; ++ i ) if ( i < rev[i] ) A[i] ^= A[rev[i]] ^= A[i] ^= A[rev[i]];
for ( int i = 2, stp = 1; i <= n; i <<= 1, stp <<= 1 ) {
int w = qkpow ( G, ( MOD - 1 ) / i );
if ( ! ~ tp ) w = qkpow ( w, MOD - 2 );
for ( int j = 0; j < n; j += i ) {
for ( int k = j, r = 1; k < j + stp; ++ k, r = mul ( r, w ) ) {
int ev = A[k], ov = mul ( r, A[k + stp] );
A[k] = add ( ev, ov ), A[k + stp] = sub ( ev, ov );
}
}
}
if ( ! ~ tp ) {
int invn = qkpow ( n, MOD - 2 );
for ( int i = 0; i < n; ++ i ) A[i] = mul ( A[i], invn );
}
} inline void polyInv ( const int n, const int* A, int* R ) {
static int tmp[MAXN + 5] {};
if ( n == 1 ) return void ( R[0] = qkpow ( A[0], MOD - 2 ) );
int len = 1 << adjust ( n << 1 );
polyInv ( n + 1 >> 1, A, R );
for ( int i = 0; i < n; ++ i ) tmp[i] = A[i];
NTT ( len, tmp, 1 ), NTT ( len, R, 1 );
for ( int i = 0; i < len; ++ i ) R[i] = mul ( sub ( 2, mul ( tmp[i], R[i] ) ), R[i] ), tmp[i] = 0;
NTT ( len, R, -1 );
for ( int i = n; i < len; ++ i ) R[i] = 0;
} } // namespace Poly. int main () {
int T, n = 1e5;
fac[0] = 1;
for ( int i = 1; i <= n; ++ i ) fac[i] = mul ( fac[i - 1], i );
Poly::polyInv ( n + 1, fac, F );
F[0] = ( 1 - F[0] + MOD ) % MOD;
for ( int i = 1; i <= n; ++ i ) F[i] = ( MOD - F[i] ) % MOD;
for ( scanf ( "%d", &T ); T --; ) {
scanf ( "%d", &n );
printf ( "%d\n", F[n] );
}
return 0;
}

Solution -「51nod 1514」美妙的序列的更多相关文章

  1. 【51nod 1514】 美妙的序列

    题目 我们发现我们得正难则反 还是设\(f_i\)表示长度为\(i\)的序列个数 考虑容斥 \[f_i=i!-\sum_{j=1}^{i-1}f_j(i-j)!\] \(i!\)显然是总方案数,我们减 ...

  2. Solution -「51nod 1868」彩色树

    \(\mathcal{Description}\)   Link & 双倍经验 Link.   给定一棵 \(n\) 个结点的树,每个结点有一种颜色.记 \(g(u,v)\) 表示 \(u\) ...

  3. Solution -「51nod 1355」斐波那契的最小公倍数

    \(\mathcal{Description}\)   Link.   令 \(f\) 为 \(\text{Fibonacci}\) 数列,给定 \(\{a_n\}\),求: \[\operatorn ...

  4. Solution -「51nod 1584」加权约数和

    \(\mathcal{Description}\)   Link.   令 \(\sigma(n)\) 为 \(n\) 的约数之和.求: \[\sum_{i=1}^n\sum_{j=1}^n\max\ ...

  5. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  6. Solution -「ZJOI 2020」「洛谷 P6631」序列

    \(\mathcal{Description}\)   Link.   给定一个长为 \(n\) 的非负整数序列 \(\lang a_n\rang\),你可以进行如下操作: 取 \([l,r]\),将 ...

  7. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  8. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

  9. Solution -「CF 1491H」Yuezheng Ling and Dynamic Tree

    \(\mathcal{Description}\)   Link. 做题原因:题目名.   给定一个长度 \(n-1\) 的序列 \(\{a_2,a_3,\cdots,a_n\}\),其描述了一棵 \ ...

随机推荐

  1. [ bootstrap ] 图片内容占用padding的范围,如何解决?

    问题描述: 从效果图看到,图片内容占据了padding的范围,怎么解决呢? html代码 <div class="container"> <div class=& ...

  2. linux 查看历史命令 history命令

    1.history命令 "history"命令就是历史记录.它显示了在终端中所执行过的所有命令的历史. history //显示终端执行过的命令 history 10 //显示最近 ...

  3. Keepalived高可用、四层负载均衡

    目录 Keepalived高可用 高可用简介 常用的工具 问题 名称解释 VRRP协议 部署keepalived 下载安装 Keepalived配置 保证nginx配置一样 解决keepalived的 ...

  4. Spring Boot Admin,贼好使!

    Spring Boot Admin(SBA)是一个开源的社区项目,用于管理和监控 Spring Boot 应用程序.应用程序可以通过 http 的方式,或 Spring Cloud 服务发现机制注册到 ...

  5. 通过HTML+CSS+Javascript实现向下滚动滚动条出现导航栏并出现回到顶部按钮点击按钮回到顶部(一)

    回到顶部实例一 效果:默认隐藏导航栏,当滚动条滚到超过300px后导航栏和按钮出现,点击回到顶部按钮回到顶部,并隐藏导航栏和按钮(导航栏和按钮都是固定定位) <!doctype html> ...

  6. zookeeper,kafka,redis等分布式框架的主从同步策略

    1 zookeeper选主机制 1.1 LeaderElection选举算法 选举线程由当前Server发起选举的线程担任,他主要的功能对投票结果进行统计,并选出推荐的Server.选举线程首先向所有 ...

  7. gin中只绑定url查询字符串

    package main import ( "github.com/gin-gonic/gin" "log" ) type Person struct{ Nam ...

  8. K8S配置多集群访问

    中文官档: http://docs.kubernetes.org.cn/823.html 背景:我们通过会有多个k8s集群,例如集群(cn-k8s)和集群(jp-k8s),那个就需要有一台服务器可以同 ...

  9. mysql新增用户无法登陆问题解决ERROR 1045 (28000)

    mysql增加新用户无法登陆解决方法 ERROR 1045 (28000): Access denied for user 'appadmin'@'localhost' (using password ...

  10. Kubernetes之日志和监控(十五)

    一.日志和监控 1.1.Log 1.1.1.容器级别 通过docker命令查看容器级别的日志 docker ps --->containerid docker logs containerid ...