Description

如果对于一个 \(1\sim n\) 的排列满足:

在 \(1\sim n-1\) 这些位置之后将序列断开,使得总可以从右边找一个数,使得该数不会比左边所有数都大,则称该序列是“美妙的”。

给出 \(n\) ,求出长度为 \(n\) 的美妙的序列的数量。多组数据。 \(T,n\leq 10^5\)。对 \(998244353\) 取模。

Solution

暴力DP是 \(O(Tn^2)\) 的。我们需要发现题目的隐藏性质。

如果某个排列不是美妙的,那一定存在一个位置 \(k\) ,使得 \(k\) 右边的最小值大于左边的最大值。也就是说,\(k\) 左边是一个 \(1\sim k\) 的排列。

问题就转化成了求有多少长度为 \(n\) 的排列,使得任意一个前缀都不是 \(1\sim k\) 的排列。

考虑 \(DP\) 。设 \(f[i]\) 表示长度为 \(i\) 的美妙的排列个数。有转移:

\[f[n]=n!-\sum_{i=1}^{n-1}i!\cdot f[n-i]\quad f[0]=0
\]

这个转移的含义是用总方案数减去不合法的方案数,也就是减去所有不美妙的排列。于是枚举最靠右不能满足要求的位置,然后把序列划分成两端。前一段是一个 \(1\sim k\) 的排列,后一段一定是一个美妙的序列(不然一定可以找到一个更靠右的不满足题意的位置)。

这时候就可以分治FFT了。但是别着急,一般分治FFT能做的多项式求逆都可以做。再推几步式子:

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

移项:

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

由于有 \(f[0]=0\) 的特殊情况所以需要特殊考虑:

\[\text{当n=0时}\quad \sum_{i=0}^n i!\cdot f[n-i]+1=n!
\]

于是令 \(F\) 为 \(f\) 的生成函数,\(G=\sum\limits_{i=0}^\infty i!\cdot x^i\),于是就有 \(F\times G+1=G\),移项可以得到:

\[F=1-\frac1{G}
\]

多项式求逆即可。复杂度 \(O(n\log n)\)。

Code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
#define int long long
const int n=1e5;
const int N=4e5+5;
const int mod=998244353; int fac[N];
int tmpa[N];
int b[N],c[N];
int lim,rev[N]; int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
} int ksm(int a,int b=mod-2,int ans=1){
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;b>>=1;
} return ans;
} void ntt(int *f,int opt){
for(int i=1;i<lim;i++) if(i<rev[i]) swap(f[i],f[rev[i]]);
for(int mid=1;mid<lim;mid<<=1){
int tmp=ksm(3,(mod-1)/(mid<<1));
if(opt<0) tmp=ksm(tmp);
for(int R=mid<<1,j=0;j<lim;j+=R){
int w=1;
for(int k=0;k<mid;k++,w=w*tmp%mod){
int x=f[j+k],y=w*f[j+k+mid]%mod;
f[j+k]=(x+y)%mod,f[j+k+mid]=(mod+x-y)%mod;
}
}
} if(opt<0)
for(int in=ksm(lim),i=0;i<lim;i++) f[i]=f[i]*in%mod;
} void solveinv(int len,int *a,int *b){
if(!len) return b[0]=ksm(a[0]),void();
solveinv(len>>1,a,b);lim=len+len;
for(int i=1;i<lim;i++) rev[i]=(rev[i>>1]>>1)|(i&1?lim>>1:0);
for(int i=0;i<len;i++) tmpa[i]=a[i];
ntt(tmpa,1),ntt(b,1);
for(int i=0;i<lim;i++) b[i]=b[i]*(2ll-tmpa[i]*b[i]%mod+mod)%mod;
ntt(b,-1);
for(int i=len;i<lim;i++) b[i]=0;
for(int i=0;i<lim;i++) tmpa[i]=0;
} signed main(){
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
solveinv(131072,fac,b);
for(int i=1;i<=n;i++) b[i]=mod-b[i];
int T=getint();
while(T--){
int x=getint();
printf("%lld\n",b[x]);
} return 0;
}

[51nod1514] 美妙的序列的更多相关文章

  1. Solution -「51nod 1514」美妙的序列

    \(\mathcal{Description}\)   Link.   称排列 \(\{p_n\}\) 美妙,当且仅当 \((\forall i\in[1,n))(\max_{j\in[1,i]}\{ ...

  2. NTT【51nod】1514 美妙的序列

    题意:1~n 的全排列中,有多少个排列满足任意从中间切成两段后,左边段的最大值大于右边段的最小值? 例如:n为3时有3种 2 3 1 3 1 2 3 2 1 解释:比如 2 3 1 (2) (3 1) ...

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

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

  4. 51nod 1514 美妙的序列

    Description 长度为n的排列,且满足从中间任意位置划分为两个非空数列后,左边的最大值>右边的最小值.问这样的排列有多少个%998244353 题面 Solution 正难则反 \(f[ ...

  5. 51nod 1514 美妙的序列 分治NTT + 容斥

    Code: #include<bits/stdc++.h> #define ll long long #define mod 998244353 #define maxn 400000 # ...

  6. 模拟赛1101d1

    完美的序列(sequence)Time Limit:1000ms Memory Limit:64MB题目描述LYK 认为一个完美的序列要满足这样的条件:对于任意两个位置上的数都不相同.然而并不是所有的 ...

  7. 济南学习 Day 4 T1 am

    完美的序列(sequence)Time Limit:1000ms Memory Limit:64MB题目描述LYK 认为一个完美的序列要满足这样的条件:对于任意两个位置上的数都不相同.然而并不是所有的 ...

  8. 11.1 morning

    完美的序列(sequence)Time Limit:1000ms Memory Limit:64MB题目描述LYK 认为一个完美的序列要满足这样的条件:对于任意两个位置上的数都不相同.然而并不是所有的 ...

  9. 【CODEVS 6384 大米兔学全排列】

    ·大米兔学习全排列,还有一些逆序对,还有一棵二叉索引树.· ·分析:       首先肯定不是像题目上说的那样,使用next_permutation去完成这道题,因为就算是线性的它也不能承受庞大的排列 ...

随机推荐

  1. SPARK安装二:HADOOP集群部署

    一.hadoop下载 使用2.7.6版本,因为公司生产环境是这个版本 cd /opt wget http://mirrors.hust.edu.cn/apache/hadoop/common/hado ...

  2. AX_Function

    formrun.owner().GetItemId() if (fr.name() == formstr(inventTransEditDimensions) || fr.name() == form ...

  3. String 常用函数

    判断字符串是否包含指定字符str.contains("string"); 查找指定字符索引str.indexOf("s"'); 查找最后出现的字符索引str.i ...

  4. MUI 里js动态添加数字输入框后,增加、减少按钮无效

    numbox 的自动初化是在 mui.ready 时完成的mui 页面默认会自动初始化页面中的所有数字输入框,动态构造的 DOM 需要进行手动初始化.比如:您动态创建了一个 ID 为 abc 的数字输 ...

  5. JQuery对checkbox的操作

    对复选框组的全选.全不选.不全选,获取选中的复选框的值的操作 点击全选按钮,复选框组全部选中或者全部取消. 实现全选按钮和复选框组的联动,当复选框组中有一个没有被选中后,那么id=‘checkedAl ...

  6. Kotlin 开篇

    Kotlin 是一个基于 JVM 的新的编程语言,由 JetBrains 开发官网地址:http://kotlinlang.org.JetBrains,作为目前广受欢迎的 Java IDE Intel ...

  7. Dockerfile 构建容器

    本文是最简单的Dockerfile教程,创建tomcat容器,并跑自己的java程序 首先需要准备几个东西 1.你的java web(test.war) 程序,最好打包成一个 war:(主要是没测试 ...

  8. InnoDB体系架构(二)内存

    InnoDB体系架构(二)内存 上篇文章 InnoDB体系架构(一)后台线程 介绍了MySQL InnoDB存储引擎后台线程:Master Thread.IO Thread.Purge Thread. ...

  9. Go语言数据类型

    目录 基本数据类型说明 整型 浮点型 字符 字符类型本质探讨 布尔型 字符串 指针 值类型与引用类型 基本数据类型默认值 基本数据类型相互转换 注意事项 其他基本类型转string类型 string类 ...

  10. Eclipse 刚检出的项目 Build path 的时候提示 No action available

    问题: 从SVN检出来的项目发现无法进行build path,也不报错,任何类之间也无法关联(Ctrl+右键无法点进去). 原因: .classpath是Eclipse的工程文件,别人没有将工程的信息 ...