题目

CF960G

做法

设\(f(i,j)\)为\(i\)个数的序列,有\(j\)个前缀最大值的方案数

我们考虑每次添一个最小数,则有:\(f(i,j)=f(i-1,j)+(i-1)*f(i-1,j-1)\),显然这是第一类斯特林数

从而我们得到一个朴素的答案:$$Ans=\sum\limits_{i=1}{n}f_{i,a-1}×f_{n-1-i,b-1}×C_{n-1}i$$

理解:枚举\(i+1\)为最大值添的位置,则已限制了前缀最值个数及后缀最值个数,然后再乘上前半部分所填的数

观察\(f_{i,a-1}×f_{n-1-i,b-1}\),发现第一维和唯一:$$Ans=\begin{bmatrix}n-1\a+b-2\end{bmatrix}C_{a+b-2}^{a-1}$$

可能会有点难理解:等同于分类成\(a+b-2\)个环,而环是不考虑顺序的,所以我们选择不考虑打乱顺序地选择环

至此,我们唯一需要的就是快速求出第一类斯特林数\(\begin{bmatrix}n-1\\a+b-2\end{bmatrix}\)

即使是单个数也无法有特殊的公式快速得出,所以我们用与求整行第一类斯特林数的方法求出

\(O(nlog^2n)\)的方法已经烂大街了,分治一下就行

\(O(nlogn)\):由于涉及到公式推倒,不是本题解的重点

移步浅谈斯特林数与斯特林反演,内有详细证明推倒及代码

Code

#include<bits/stdc++.h>
typedef int LL;
const LL mod=998244353,g=3,_g=332748118,maxn=2e5+9;
inline LL Pow(LL base,LL b){
LL ret(1);
while(b){
if(b&1) ret=1ll*ret*base%mod; base=1ll*base*base%mod; b>>=1;
}return ret;
}
LL r[maxn],W[maxn];
inline LL Fir(LL n){
LL limit(1),len(0),up(n<<1);
while(limit<up){
limit<<=1; ++len;
}
for(LL i=0;i<limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<len-1);
return limit;
}
inline void NTT(LL *a,LL n,LL type){
for(LL i=0;i<n;++i) if(i<r[i]) std::swap(a[i],a[r[i]]);
for(LL mid=1;mid<n;mid<<=1){
LL wn(Pow(type?g:_g,(mod-1)/(mid<<1)));
W[0]=1; for(LL i=1;i<mid;++i) W[i]=1ll*W[i-1]*wn%mod;
for(LL R=mid<<1,j=0;j<n;j+=R)
for(LL k=0;k<mid;++k){
LL x(a[j+k]),y(1ll*W[k]*a[j+mid+k]%mod);
a[j+k]=1ll*(x+y)%mod; a[j+mid+k]=1ll*(x-y+mod)%mod;
}
}
}
LL T[maxn],F[maxn],H[maxn],fac[maxn],fav[maxn],tmp[maxn],sum[maxn],B[maxn];
inline LL Mul(LL n,LL *a,LL *b,LL *ans){
LL limit(Fir(n));
NTT(a,limit,1); NTT(b,limit,1);
for(LL i=0;i<limit;++i) ans[i]=1ll*a[i]*b[i]%mod;
NTT(ans,limit,0);
for(LL i=((n-1)<<1)+1;i<limit;++i) a[i]=b[i]=0;
return Pow(limit,mod-2);
}
inline void Solve(LL n,LL *a){
if(!n){ a[0]=1; return; }
if(n==1){ a[1]=1; return; }
LL len(n/2);
Solve(len,a);
for(LL i=0;i<=len;++i){
F[i]=1ll*Pow(len,i)*fav[i]%mod;
H[i]=1ll*fac[i]*a[i]%mod;
}
std::reverse(H,H+len+1); LL limit(Fir(len+1));
NTT(F,limit,1); NTT(H,limit,1);
for(LL i=0;i<limit;++i) F[i]=1ll*F[i]*H[i]%mod;
NTT(F,limit,0);
LL ty(Pow(limit,mod-2));
for(LL i=0;i<=len;++i) tmp[i]=1ll*F[len-i]*ty%mod*Pow(fac[i],mod-2)%mod;
for(LL i=(len<<1);i<=limit;++i) F[i]=H[i]=0; LL val(Mul(len+1,a,tmp,B));
for(LL i=0;i<=(len<<1);++i) a[i]=1ll*B[i]*val%mod; if(n&1)
for(LL i=n;i>=1;--i) a[i]=1ll*(a[i-1]+1ll*(n-1)*a[i]%mod)%mod;
}
LL n,a,b,m;
LL ans[maxn];
int main(){
scanf("%d%d%d",&n,&a,&b);
LL val;
val=fac[0]=fac[1]=1;
for(LL i=2;i<=n;++i) val=fac[i]=1ll*val*i%mod;
val=fav[n]=Pow(fac[n],mod-2);
for(LL i=n;i>=1;--i) val=fav[i-1]=1ll*val*i%mod;
Solve(n-1,ans); n=a+b-2; m=a-1;
printf("%d\n",1ll*ans[n]*fac[n]%mod*fav[m]%mod*fav[n-m]%mod%mod);
}

CF960G(第一类斯特林数)的更多相关文章

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

    [CF960G]Bandit Blues(第一类斯特林数,FFT) 题面 洛谷 CF 求前缀最大值有\(a\)个,后缀最大值有\(b\)个的长度为\(n\)的排列个数. 题解 完完全全就是[FJOI] ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. P4609 [FJOI2016]建筑师(第一类斯特林数)

    传送门 没想到连黑题都会有双倍经验的 其实这题本质上是和CF960G Bandit Blues一样的,不过那里是要用分治FFT预处理第一类斯特林数,这里直接打表预处理第一类斯特林数就可以了 //min ...

随机推荐

  1. linux 知识点拾遗

    文件名称 在 Linux 底下,每个档案或文件夹的文件名称最长能够到达 255 的字符,加上完整路径时,最长可达 4096 个字符; 因为 Linux 在文字接口下的一些指令操作关系,一般来说,您在设 ...

  2. Dynamics CRM 系统自己定义部分的语言翻译

    Dynamics CRM 自带语言切换功能,在官网下载所需语言包安装后,在设置语言中就能看到你所加入的语言.勾选要启用的语言应用就可以.再打开系统设置--语言就能看到可更改用户界面语言的显示了. wa ...

  3. js 代码优化 (写的可以)

    Javascript是一门非常灵活的语言,我们可以随心所欲的书写各种风格的代码,不同风格的代码也必然也会导致执行效率的差异,开发过程中零零散散地接触到许多提高代码性能的方法,整理一下平时比较常见并且容 ...

  4. 用MathType编辑反三角函数的方法

    在使用文档写数学类的文章时候,常常会涉及到一些数学公式,由于数学公式中包含了很多的数学符号,如果使用文档自带的公式编辑器往往会发现很多的符号都不全或者不符合自己的要求.这个时候就需要一款专业的数学公式 ...

  5. 到底什么是hash

    1.什么是hash算法 Hash(散列.杂凑)算法,是把任意长度的输入通过特定的算法变换成固定长度的输出,输出的值就是hash值.这个特定的算法就叫hash算法,hash算法并不是一个固定不变的算法. ...

  6. 最近5年133个Java面试问题列表

    Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来越高级,面试官问的问题也更深入. 在我 ...

  7. python 的时间复杂度

    Python内置方法的时间复杂度 本文翻译自Python Wiki 本文基于GPL v2协议,转载请保留此协议. 本页面涵盖了Python中若干方法的时间复杂度(或者叫“大欧”,“Big O”).该时 ...

  8. 【BZOJ1822】[JSOI2010]Frozen Nova 冷冻波 几何+二分+网络流

    [BZOJ1822][JSOI2010]Frozen Nova 冷冻波 Description WJJ喜欢“魔兽争霸”这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀 ...

  9. iOS 将金钱变为逗号形式

    ; NSNumberFormatter * formatter = [NSNumberFormatter new]; [formatter setNumberStyle:NSNumberFormatt ...

  10. 爬虫入门【11】Pyspider框架入门—使用HTML和CSS选择器下载小说

    开始之前 首先我们要安装好pyspider,可以参考上一篇文章. 从一个web页面抓取信息的过程包括: 1.找到页面上包含的URL信息,这个url包含我们想要的信息 2.通过HTTP来获取页面内容 3 ...