【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. flask-script&flask-migrate使用

    一.简介 Flask-script扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell.设置数据库的脚本.cronjobs及其他运行在web应用之外的 ...

  2. [Deep-Learning-with-Python]GAN图片生成

    GAN 由Goodfellow等人于2014年引入的生成对抗网络(GAN)是用于学习图像潜在空间的VAE的替代方案.它们通过强制生成的图像在统计上几乎与真实图像几乎无法区分,从而能够生成相当逼真的合成 ...

  3. synchronized和Lock的异同

    JAVA语言使用两种机制来实现堆某种共享资源的同步,synchronized和Lock.其中,synchronized使用Object对象本身的notify.wait.notifyAll调度机制,而l ...

  4. EXPERT FOR SQL SERVER诊断系列--索引

    概述   索引设计是数据库设计中比较重要的一个环节,对数据库的性能起着至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员因为不恰当的创建索引,最后使得其 ...

  5. Linux ip forward

    Linux 默认带有 ip forward 功能,只不过因为各种原因,默认的配置把该功能关闭了.本文通过 demo 来演示 Linux 的 ip forward 功能,具体场景为:开启 Linux 的 ...

  6. 树莓派3代b型静态IP设置,和ssh的wlan配置

    https://blog.csdn.net/qq_36305492/article/details/78607557

  7. Eddy's mistakes HDU

    链接 [http://acm.hdu.edu.cn/showproblem.php?pid=1161] 题意 把字符串中大写字母变为小写 . 分析 主要是含有空格的字符串如何读入,用getline(c ...

  8. D. Bicolorings

    传送门 [http://codeforces.com/contest/1051/problem/D] 题意 相当于有个2列n行得棋盘,棋盘上的格子只能是黑或者白,问你联通块为k得方案数有多少,结果对 ...

  9. 【个人阅读作业】软件工程M1/M2总结

    链接:”看<快速软件开发>的五个问题“ http://www.cnblogs.com/leiyy/p/4027759.html 一.较为明白的问题 1. 在文章的第一个关于Square_T ...

  10. 《Linux内核设计与实现》读书笔记 18

    第十八章调试 18.1 准备开始 一个bug:大部分bug通常都不是行为可靠而且定义明确的 一个藏匿bug的内核版本:找出bug首先出现的版本 相关内核代码的知识和运气 18.2内核中的bug 可以有 ...