题目

给你三个正整数 \(n\),\(a\),\(b\),定义 \(A\) 为一个排列中是前缀最大值的数的个数,

定义 \(B\) 为一个排列中是后缀最大值的数的个数,求长度为 \(n\) 的排列中满足 \(A = a\) 且 \(B = b\) 的排列个数。


分析

最大值一定是 \(n\),左边有 \(a-1\) 的前缀最大值,右边有 \(b-1\) 的后缀最大值。

假设已经钦定 \(a+b-2\) 个最大值,等于要将 \(n-1\) 个数分成 \(a+b-2\) 个部分且最大值要顶在最外面,也就是 \(a+b-2\) 个圆排列,

然后还要把 \(a+b-2\) 个部分给左边 \(a-1\) 个,那也就是 \(C(a+b-2,a-1)*Stir(n-1,a+b-2)\),求第一类斯特林数即可


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <algorithm>
#define rr register
#define mem(f,n) memset(f,0,sizeof(int)*(n))
#define cpy(f,g,n) memcpy(f,g,sizeof(int)*(n))
using namespace std;
const int mod=998244353,inv3=332748118,N=200011;
typedef long long lll; typedef unsigned long long ull;
int n,m,Gmi[31],Imi[31],len,fac[N],X,Y,inv[N],ff[N<<1],gg[N<<1],tt[N<<1];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed ksm(int x,int y){
rr int ans=1;
for (;y;y>>=1,x=1ll*x*x%mod)
if (y&1) ans=1ll*ans*x%mod;
return ans;
}
namespace Theoretic{
int rev[N<<1],LAST; ull Wt[N<<1],F[N<<1];
inline void Pro(int n){
if (LAST==n) return; LAST=n,Wt[0]=1;
for (rr int i=0;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)?n>>1:0);
}
inline void NTT(int *f,int n,int op){
Pro(n);
for (rr int i=0;i<n;++i) F[i]=f[rev[i]];
for (rr int o=1,len=1;len<n;++o,len<<=1){
rr int W=(op==1)?Gmi[o]:Imi[o];
for (rr int j=1;j<len;++j) Wt[j]=Wt[j-1]*W%mod;
for (rr int i=0;i<n;i+=len+len)
for (rr int j=0;j<len;++j){
rr int t=Wt[j]*F[i|j|len]%mod;
F[i|j|len]=F[i|j]+mod-t,F[i|j]+=t;
}
if (o==10) for (rr int j=0;j<n;++j) F[j]%=mod;
}
if (op==-1){
rr int invn=ksm(n,mod-2);
for (rr int i=0;i<n;++i) F[i]=F[i]%mod*invn%mod;
}else for (rr int i=0;i<n;++i) F[i]%=mod;
for (rr int i=0;i<n;++i) f[i]=F[i];
}
inline void Cb(int *f,int *g,int n){
for (rr int i=0;i<n;++i) f[i]=1ll*f[i]*g[i]%mod;
}
inline void Shift(int *f,int *g,int n,int sh){
for (rr int i=0;i<n;++i) tt[n-i-1]=1ll*g[i]*fac[i]%mod;
for (rr int i=0,t=1;i<n;++i,t=1ll*t*sh%mod) f[i]=1ll*t*inv[i]%mod;
rr int len=1; for (;len<n+n;len<<=1);
NTT(tt,len,1),NTT(f,len,1),Cb(tt,f,len),NTT(tt,len,-1);
for (rr int i=0;i<n;++i) f[n-i-1]=1ll*tt[i]*inv[n-i-1]%mod;
mem(f+n,len-n),mem(tt,len);
}
inline void Doubly(int *f,int n){
if (!n) {f[0]=1; return;}
else if (n&1){
Doubly(f,n-1),f[n]=0;
for (rr int i=n;i;--i)
f[i]=(f[i-1]+1ll*f[i]*(n-1)%mod)%mod;
f[0]=1ll*f[0]*(n-1)%mod;
}else{
Doubly(f,n>>1);
Shift(gg,f,(n>>1)+1,n>>1);
rr int len=1; for (;len<n+2;len<<=1);
NTT(f,len,1),NTT(gg,len,1),Cb(f,gg,len),
NTT(f,len,-1),mem(gg,len),mem(f+n+2,len-n-2);
}
}
}
inline void GmiImi(){
for (rr int i=0;i<31;++i) Gmi[i]=ksm(3,(mod-1)/(1<<i));
for (rr int i=0;i<31;++i) Imi[i]=ksm(inv3,(mod-1)/(1<<i));
}
signed main(){
n=iut(),X=iut(),Y=iut(),GmiImi(),fac[0]=fac[1]=inv[0]=inv[1]=1;
for (rr int i=2;i<=n*2;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for (rr int i=2;i<=n*2;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i]*inv[i-1]%mod;
Theoretic::Doubly(ff,n-1);
return !printf("%lld",1ll*ff[X+Y-2]*fac[X+Y-2]%mod*inv[X-1]%mod*inv[Y-1]%mod);
}

#第一类斯特林数,NTT#CF960G Bandit Blues的更多相关文章

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

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

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

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

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

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

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

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

  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. CF960G-Bandit Blues【第一类斯特林数,分治,NTT】

    正题 题目链接:https://www.luogu.com.cn/problem/CF960G 题目大意 求有多少个长度为\(n\)的排列,使得有\(A\)个前缀最大值和\(B\)个后缀最大值. \( ...

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

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

随机推荐

  1. 常用Windows控制台命令

    查看网络连接信息 1.查看所有网络连接 netstat -ano -a 显示所有连接和侦听端口. -n 以数字形式显示地址和端口号. -o 显示拥有的与每个连接关联的进程 ID. 详细的使用方式使用n ...

  2. 单表查询,多表查询,子查询---day37

    1.单表查询 # ### part1 单表查询 # sql 查询语句的完整语法 '''select..from..where..group by..having..order by..limit..' ...

  3. 【Python语法糖】闭包和装饰器

    Python闭包和装饰器 参考: https://zhuanlan.zhihu.com/p/453787908 https://www.bilibili.com/video/BV1JW411i7HR/ ...

  4. 学会了MySql高级查询让你在工作中游刃有余

    一.单元概述 通过本章的学习能够理解MySQL数据库中分组查询的含义,掌握常用分组函数的使用,掌握GROUP BY子句的使用规则,掌握分组后数据结果的条件过滤,掌握SELECT语句执行过程,理解子查询 ...

  5. SpringCloud使用Kafka消费者

    目录 POM文件配置 创建kafka配置 系统配置信息 启动入口 POM文件配置 <project xmlns="http://maven.apache.org/POM/4.0.0&q ...

  6. macOS通过ssh使用PEM登录

    在win上面可以使用XSHELL来登录类似于亚马逊这样的安全服务器,在mac上面就可以使用系统自带的命令工具来连接 使用命令 ssh -i key.pem [server] 如下: ssh -i ke ...

  7. DataGear 自定义数据可视化看板的图表主题

    DataGear 看板的 dg-chart-theme 属性,提供了简单且强大的自定义图表主题功能. 通常,只需要设置其color.backgroundColor.actualBackgroundCo ...

  8. 聊聊微信小程序的流式(stream)响应请求

    场景:类似ChatGPT的逐字显示效果. 流程:服务端我用Python的flask框架(向外提供API接口)实现,服务部署在replit上,Python调用azure 的chatgpt服务(需要申请) ...

  9. Java 常用类 于 StringBuffer 和 StringBuilder的使用 + String三者的异同

    1 package com.bytezero.stringclass; 2 3 import org.junit.Test; 4 5 /** 6 * 关于 StringBuffer 和 StringB ...

  10. 详解Python魔法函数,__init__,__str__,__del__

    1.简介 Python作为一门灵活而强大的编程语言,提供了许多特殊的方法,被称为魔法函数(Magic methods).这些魔法函数以双下划线开头和结尾,能够让我们自定义类的行为,使得Python更加 ...