【CF960G】Bandit Blues(第一类斯特林数,FFT)

题面

洛谷

CF

求前缀最大值有\(a\)个,后缀最大值有\(b\)个的长度为\(n\)的排列个数。

题解

完完全全就是【FJOI】建筑师的加强版本。

显然每一个前缀最大值和一段连续的区间构成了一个环排列,显然每个前缀最大值就是这个环中的最大值。而全局最大值一定把前后缀最大值分开。

所以答案考虑除最大值外,左侧需要\(a-1\)个前缀最大值,右侧需要\(b-1\)个前缀最大值。也就是一共要\(a+b-2\)个环,那么这一部分的贡献是\(\begin{bmatrix}n-1\\a+b-2\end{bmatrix}\)。而环在左右随意分配,所以再乘上一个\(a+b-2\choose a-1\)。

解释一个小问题,为什么不需要考虑环的最大值的大小关系,因为我们强制在排列过程中按照最大值从小往大放,而每个环因为放置的时候是一个线段,那么我们保证最大值一定在靠外侧,这样子后面的比它小的值必定不是前缀或者后缀最大值。

那么问题转化成了怎么预处理第一类斯特林数。戳这里

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define MAX 300000
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int r[MAX],W[MAX];
void NTT(int *P,int opt,int N)
{
int l=0;for(int i=1;i<N;i<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
{
int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
{
int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD;
P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
}
}
if(opt==-1)
{
reverse(&P[1],&P[N]);
for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
}
}
int S[MAX],jc[MAX],jv[MAX],inv[MAX];
int C(int n,int m){if(n<m)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
int A[MAX],B[MAX],pw[MAX];
void Solve(int len)
{
if(len==0){S[0]=1;return;}
if(len==1){S[1]=1;return;}
if(len&1)
{
Solve(len-1);
for(int i=len;i;--i)S[i]=(S[i-1]+1ll*S[i]*(len-1))%MOD;
}
else
{
Solve(len>>1);int l=len>>1,N;
for(N=1;N<=len;N<<=1);
pw[0]=1;for(int i=1;i<=l;++i)pw[i]=1ll*pw[i-1]*l%MOD;
for(int i=0;i<=l;++i)A[i]=1ll*S[i]*jc[i]%MOD;
for(int i=0;i<=l;++i)B[i]=1ll*pw[i]*jv[i]%MOD;
reverse(&B[0],&B[l+1]);
NTT(A,1,N);NTT(B,1,N);
for(int i=0;i<N;++i)A[i]=1ll*A[i]*B[i]%MOD;
NTT(A,-1,N);
for(int i=0;i<=l;++i)A[i]=1ll*A[i+l]*jv[i]%MOD;
for(int i=l+1;i<N;++i)A[i]=B[i]=0;
for(int i=0;i<=l;++i)B[i]=S[i];
NTT(A,1,N);NTT(B,1,N);
for(int i=0;i<N;++i)A[i]=1ll*A[i]*B[i]%MOD;
NTT(A,-1,N);
for(int i=0;i<=len;++i)S[i]=A[i];
for(int i=0;i<N;++i)A[i]=B[i]=0;
}
}
int n,a,b;
int main()
{
n=read();a=read();b=read();
jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=1;i<=max(a+b,n);++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=2;i<=max(a+b,n);++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=max(a+b,n);++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
Solve(n-1);int ans=1ll*C(a+b-2,a-1)*S[a+b-2]%MOD;
printf("%d\n",ans);
return 0;
}

【CF960G】Bandit Blues(第一类斯特林数,FFT)的更多相关文章

  1. CF960G Bandit Blues 第一类斯特林数+分治+FFT

    题目传送门 https://codeforces.com/contest/960/problem/G 题解 首先整个排列的最大值一定是 \(A\) 个前缀最大值的最后一个,也是 \(B\) 个后缀最大 ...

  2. CF960G Bandit Blues 第一类斯特林数、NTT、分治/倍增

    传送门 弱化版:FJOI2016 建筑师 由上面一题得到我们需要求的是\(\begin{bmatrix} N - 1 \\ A + B - 2 \end{bmatrix} \times \binom ...

  3. [CF960G]Bandit Blues(第一类斯特林数+分治卷积)

    Solution: ​ 先考虑前缀,设 \(f(i, j)\) 为长度为 \(i\) 的排列中满足前缀最大值为自己的数有 \(j\) 个的排列数. 假设新加一个数 \(i+1\) 那么会有: \[ f ...

  4. Codeforces960G Bandit Blues 【斯特林数】【FFT】

    题目大意: 求满足比之前的任何数小的有A个,比之后的任何数小的有B个的长度为n的排列个数. 题目分析: 首先写出递推式,设s(n,k)表示长度为n的排列,比之前的数小的数有k个. 我们假设新加入的数为 ...

  5. CF960G Bandit Blues 【第一类斯特林数 + 分治NTT】

    题目链接 CF960G 题解 同FJOI2016只不过数据范围变大了 考虑如何预处理第一类斯特林数 性质 \[x^{\overline{n}} = \sum\limits_{i = 0}^{n}\be ...

  6. CF960G Bandit Blues(第一类斯特林数)

    传送门 可以去看看litble巨巨关于第一类斯特林数的总结 设\(f(i,j)\)为\(i\)个数的排列中有\(j\)个数是前缀最大数的方案数,枚举最小的数的位置,则有递推式\(f(i,j)=f(i- ...

  7. CF960G Bandit Blues 分治+NTT(第一类斯特林数)

    $ \color{#0066ff}{ 题目描述 }$ 给你三个正整数 \(n\),\(a\),\(b\),定义 \(A\) 为一个排列中是前缀最大值的数的个数,定义 \(B\) 为一个排列中是后缀最大 ...

  8. 【cf960G】G. Bandit Blues(第一类斯特林数)

    传送门 题意: 现在有一个人分别从\(1,n\)两点出发,包中有一个物品价值一开始为\(0\),每遇到一个价值比包中物品高的就交换两个物品. 现在已知这个人从左边出发交换了\(a\)次,从右边出发交换 ...

  9. CF960G(第一类斯特林数)

    题目 CF960G 做法 设\(f(i,j)\)为\(i\)个数的序列,有\(j\)个前缀最大值的方案数 我们考虑每次添一个最小数,则有:\(f(i,j)=f(i-1,j)+(i-1)*f(i-1,j ...

随机推荐

  1. ASP.NET MVC中jQuery与angularjs混合应用传参并绑定数据

    要求是这样子的,在一个列表页中,用户点击详细铵钮,带记录的主键值至另一页.在另一外页中,获取记录数据,然后显示此记录数据在网页上. 先用动图演示: 昨天有分享为ng-click传递参数 <ang ...

  2. China Intelligent Office Summit(2018.11.21)

    时间:2018.11.21地点:中关村软件园国际会议中心

  3. LiveCharts文档-4基本绘图-3其他

    原文:LiveCharts文档-4基本绘图-3其他 4基本绘图-3其他 因为每个图表的使用方法大同小异,所以不再啰嗦重复,具体直接看这个链接里的介绍.原文链接 其他的图表类型有 基本堆叠图 基本条形图 ...

  4. ubuntu 中iptables

    ubuntu中启动及关闭iptables 在ubuntu中由于不存在 /etc/init.d/iptales文件,所以无法使用service等命令来启动iptables,需要用modprobe命令. ...

  5. [UWP 自定义控件]了解模板化控件(10):原则与技巧

    1. 原则 推荐以符合以下原则的方式编写模板化控件: 选择合适的父类:选择合适的父类可以节省大量的工作,从UWP自带的控件中选择父类是最安全的做法,通常的选择是Control.ContentContr ...

  6. M2事后分析

    计划 1. 你原计划的工作是否最后都做完了? 如果有没做完的,为什么? 修复了M1阶段的bug,整合前两组的数据.扩充功能,和学霸组达成功能上的一致,对数据库进行信息的完善. 2. 有没有发现你做了一 ...

  7. C++编写四则运算生成程序

    1.计划方案 按照预定计划,在时限为一周时,完成该程序所需时间大致如下表: PSP2.1 Personal Software Process Stages Time Planning 计划 · Est ...

  8. 《Linux内核分析》第八周笔记 进程的切换和系统的一般执行过程

    20135132陈雨鑫 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ...

  9. 读书笔记(chapter17)

    设备类型:在所有Unix系统中为了统一普通设备的操作所采用的分类 模块:Linux内核中用于按需加载和卸载目标码的机制 内核对象:内核数据结构中支持面对对象的简单操作,还支持维护对象之间的父子关系 1 ...

  10. oracle alter

    ALTER TABLE (表名) ADD CONSTRAINT (索引名);ALTER TABLE (表名) DROP CONSTRAINT (索引名); ALTER TABLE (表名) ADD ( ...