题目大意:

  求满足比之前的任何数小的有A个,比之后的任何数小的有B个的长度为n的排列个数。

题目分析:

  首先写出递推式,设s(n,k)表示长度为n的排列,比之前的数小的数有k个。

  我们假设新加入的数为1,那么s(n,k)=s(n-1,k-1)+(n-1)*s(n,k)。

  这个式子是第一类斯特林数的递推式。

  用h(n,a,b)表示满足题目给出条件的排列个数。

  得出h(n,a,b)=Σs(k,a-1)*s(n-k-1,b-1)*C(n-1,k)。直观的理解就是将原排列从最高点分成两部分,两部分分别组合然后乘起来。

  这样我们发现h(n,a,b)=s(n-1,a+b-2)*C(a+b-2,a-1)。这实际上就是给出一个a+b-2的排列,然后选出其中需要的点放到右边,我们不用考虑多余的点,因为它们的排列已经被计算。

  由于无符号第一类斯特林数对应着升幂的系数,构造x(x+1)(x+2)...(x+n-1),它的x^k的系数等于s(n,k)的值,由于最高项系数为1,所以分治FFT。

代码:

  

 #include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std; const int mod = ;
const int gg = ; int n,a,b; vector<int> res[]; int up[]; int ord[]; int fast_pow(int now,int pw){
if(pw == ) return ;
if(pw == ) return now;
int z = fast_pow(now,pw/);
z = (1ll*z*z)%mod;
if(pw & ){z= (1ll*z*now)%mod;}
return z;
} void fft(int now,int len,int f){
for(int i=;i<len;i++) if(i<ord[i]) swap(res[now][i],res[now][ord[i]]);
for(int i=;i<len;i<<=){
int wn = fast_pow(gg,(mod-)/(i<<));
if(f == -) wn = fast_pow(wn,mod-);
for(int j=;j<len;j+=(i<<)){
for(int k=,w=;k<i;k++,w = (1ll*w*wn)%mod){
int x = res[now][j+k],y = (1ll*w*res[now][j+k+i])%mod;
res[now][j+k] = (x+y)%mod;
res[now][j+k+i] = (x-y+mod)%mod;
}
}
}
if(f == -){
int iv = fast_pow(len,mod-);
for(int i=;i<len;i++) res[now][i] = (1ll*res[now][i]*iv)%mod;
}
} void multi(int p1,int p2){
int n1 = res[p1].size()-,n2 = res[p2].size()-;
int len = ,om = ;
while(len <= (n1+n2+))len<<=,om++;
for(int i=n1+;i<len;i++) res[p1].push_back();
for(int i=n2+;i<len;i++) res[p2].push_back();
for(int i=;i<len;i++) ord[i] = (ord[i>>]>>)+((i&)<<om-);
fft(p1,len,);fft(p2,len,);
for(int i=;i<len;i++){
res[p1][i] = (1ll*res[p1][i]*res[p2][i])%mod;
if(res[p1][i] < ) res[p1][i]+=mod;
}
fft(p1,len,-);
res[p2].clear();
} void divide(int l,int r,int now){
if(l == r) {up[now] = l;return;}
int mid = (l+r)/;
divide(l,mid,now<<);
divide(mid+,r,now<<|);
multi(up[now<<],up[now<<|]);
up[now] = up[now<<];
} void work(){
if(a == || b == ){puts("");return;}
if(n == ){if(a+b==)puts(""); else puts(""); return;}
int c = ;
if(a<b) swap(a,b);
if(a- > a+b-) c = ;
for(int i=;i<=a-;i++){
c = (1ll*c*(a+b--i))%mod;
c = (1ll*c*fast_pow(i,mod-))%mod;
}
for(int i=;i<n;i++) res[i].push_back(i-),res[i].push_back();
divide(,n-,);
c = (1ll*c*res[up[]][a+b-])%mod;
printf("%d",c);
} int main(){
scanf("%d%d%d",&n,&a,&b);
work();
return ;
}

Codeforces960G Bandit Blues 【斯特林数】【FFT】的更多相关文章

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

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

  2. codeforces960G. Bandit Blues

    题目链接:codeforces960G 来看看三倍经验:hdu4372 luogu4609 某蒟蒻的关于第一类斯特林数的一点理解QAQ:https://www.cnblogs.com/zhou2003 ...

  3. 【xsy1301】 原题的价值 组合数+斯特林数+FFT

    题目大意:求$n\times2^{\frac{(n-1)(n-2)/2}{2}}\sum\limits_{i=0}^{n-1}\dbinom{n-1}{i}i^k$ 数据范围:$n≤10^9$,$k≤ ...

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

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

  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、分治/倍增

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

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

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

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

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

随机推荐

  1. 由javascript的闭包引申到程序语言编译上的自由变量作用域的考量

    function foo() { var x = 10; return function bar() { console.log(x); }; } // "foo"返回的也是一个f ...

  2. NDK toolchain对应ABI

    有些时候,解决一些问题,我们需要多一些耐心. 从今天起,正式开始SkylineGlobe移动端Android版本的二次开发. Application.mk修改为NDK_TOOLCHAIN := arm ...

  3. odoo中的ORM操作

    ORM方法简介 OpenERP的关键组件, ORM是一个完整的对象关系映射层,是开发人员不必编写基本的SQL管道. 业务对象被声明继承字models.Models的python类. 这让业务对象在OR ...

  4. C# 深浅复制 MemberwiseClone(转载)

    最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考MSDN:https://docs.microsoft.com/zh-cn/dotnet/api/syst ...

  5. CF666E Forensic Examination 广义SAM、线段树合并、倍增、扫描线

    传送门 朴素想法:对\(M\)个匹配串\(T_1,...,T_M\)建立广义SAM,对于每一次询问,找到这个SAM上\(S[pl...pr]\)对应的状态,然后计算出对于每一个\(i \in [l,r ...

  6. UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树

    传送门--UOJ 传送门--LOJ 跟隔壁通道是一个类型的 要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象-- 第二棵树上的LCA显然是动不了的,因为没有其他的量 ...

  7. SQL跨服务器查询数据库

    有时候一个项目需要用到两个数据库或多个数据库而且这些数据库在不同的服务器上时,就需要通过跨服务器查找数据 在A服务器的数据库a查询服务器B的数据库b 的bb表 假如服务器B的IP地址为:10.0.22 ...

  8. C# 深浅复制 MemberwiseClone

    学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考 ...

  9. HNOI2018简要题解

    HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...

  10. 老生常谈,函数柯里化(curring)

    柯里化这个概念确实晦涩难懂,没有深入思考过的人其实真的很难明白这是一个什么东西.看起来简单.简单到或许只需要一行代码: const curry = fn => (…args) => fn. ...