【cf960G】G. Bandit Blues(第一类斯特林数)
题意:
现在有一个人分别从\(1,n\)两点出发,包中有一个物品价值一开始为\(0\),每遇到一个价值比包中物品高的就交换两个物品。
现在已知这个人从左边出发交换了\(a\)次,从右边出发交换了\(b\)次。
现在问有多少个排列满足这一条件。
思路:
- 倒过来考虑的话,显然全局最大值为最后一次交换。
- 然后左边我们会放置\(a-1\)个递增的物品,右边放\(b-1\)个递减的物品,其余的物品我们在中间部分任意放置即可,但要保证价值在一定范围。
- 将问题进一步抽象,我们即要将\(n-1\)个数划分为\(a+b-2\)个排列,因为每个排列都有一个最大值,所以一定存在一种合法放案使得每个排列中只会交换一次。
- 因为最后还有两个部分,所以还要乘以一个组合数,那么答案就是\(\displaystyle \begin{bmatrix}
n - 1 \\ a - b + 2
\end{bmatrix}\cdot {a-b+2\choose a-1}\) 。 - 那么问题就是如何快速处理一行的第一类斯特林数了。主要是通过生成函数来求解,详细内容可以见:传送门
正难则反,正过来考虑较为复杂的情况,倒过来就显得清晰很多。
代码如下:
/*
* Author: heyuhhh
* Created Time: 2019/12/15 10:30:30
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5, MOD = 998244353;
int n, a, b;
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
int inv[N], fac[N];
void init() {
fac[0] = 1;
for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
inv[N - 1] = qpow(fac[N - 1], MOD - 2);
for(int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}
ll C(int n, int m) {
return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
int r[N], W[N];
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 = qpow(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);
int inv = qpow(N, MOD - 2);
for(int i = 0; i < N; i++) P[i] = 1ll * P[i] * inv % MOD;
}
}
int S[N];
int A[N], B[N], pw[N];
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] * fac[i] % MOD;
for(int i = 0; i <= l; i++) B[i] = 1ll * pw[i] * inv[i] % MOD;
reverse(B, 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] * inv[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;
}
}
void run(){
init();
solve(5);
for(int i = 0; i <= 5; i++) cout << S[i] << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
【cf960G】G. Bandit Blues(第一类斯特林数)的更多相关文章
- CF960G Bandit Blues 第一类斯特林数、NTT、分治/倍增
传送门 弱化版:FJOI2016 建筑师 由上面一题得到我们需要求的是\(\begin{bmatrix} N - 1 \\ A + B - 2 \end{bmatrix} \times \binom ...
- [CF960G]Bandit Blues(第一类斯特林数+分治卷积)
Solution: 先考虑前缀,设 \(f(i, j)\) 为长度为 \(i\) 的排列中满足前缀最大值为自己的数有 \(j\) 个的排列数. 假设新加一个数 \(i+1\) 那么会有: \[ f ...
- CF960G Bandit Blues 第一类斯特林数+分治+FFT
题目传送门 https://codeforces.com/contest/960/problem/G 题解 首先整个排列的最大值一定是 \(A\) 个前缀最大值的最后一个,也是 \(B\) 个后缀最大 ...
- Codeforces960G Bandit Blues 【斯特林数】【FFT】
题目大意: 求满足比之前的任何数小的有A个,比之后的任何数小的有B个的长度为n的排列个数. 题目分析: 首先写出递推式,设s(n,k)表示长度为n的排列,比之前的数小的数有k个. 我们假设新加入的数为 ...
- 【CF960G】Bandit Blues(第一类斯特林数,FFT)
[CF960G]Bandit Blues(第一类斯特林数,FFT) 题面 洛谷 CF 求前缀最大值有\(a\)个,后缀最大值有\(b\)个的长度为\(n\)的排列个数. 题解 完完全全就是[FJOI] ...
- CF960G Bandit Blues 【第一类斯特林数 + 分治NTT】
题目链接 CF960G 题解 同FJOI2016只不过数据范围变大了 考虑如何预处理第一类斯特林数 性质 \[x^{\overline{n}} = \sum\limits_{i = 0}^{n}\be ...
- CF960G Bandit Blues 分治+NTT(第一类斯特林数)
$ \color{#0066ff}{ 题目描述 }$ 给你三个正整数 \(n\),\(a\),\(b\),定义 \(A\) 为一个排列中是前缀最大值的数的个数,定义 \(B\) 为一个排列中是后缀最大 ...
- CF960G Bandit Blues(第一类斯特林数)
传送门 可以去看看litble巨巨关于第一类斯特林数的总结 设\(f(i,j)\)为\(i\)个数的排列中有\(j\)个数是前缀最大数的方案数,枚举最小的数的位置,则有递推式\(f(i,j)=f(i- ...
- CF960G(第一类斯特林数)
题目 CF960G 做法 设\(f(i,j)\)为\(i\)个数的序列,有\(j\)个前缀最大值的方案数 我们考虑每次添一个最小数,则有:\(f(i,j)=f(i-1,j)+(i-1)*f(i-1,j ...
随机推荐
- Where/Order by/Ggroup by/Having使用的注意事项
1.Where.Order by.Group by .having Where作用对象是:基本表或视图,从中选出符合条件的元素. Order by 作用对象是:基本表或视图,就是排序方式,分为升序(A ...
- Socket无法通过防火墙的问题
无论是配好端口还是例外的应用程序都不行 更改本地终结点为 socket.Bind()); IPAddress.Any 不要使用127.0.0.1 不要使用127.0.0.1 不要使用127.0.0.1
- 《JavaScript 模式》知识点小抄本(下)
介绍 最近开始给自己每周订个学习任务,学习结果反馈为一篇文章的输出,做好学习记录. 这一周(02.25-03.03)我定的目标是<JavaScript 模式>的第七章学习一遍,学习结果的反 ...
- Orleans 初接触
简介 这篇随笔主要记录了自己学习Orleans的经过和理解,在学习过程中会一直更新,思路和理解可能有些偏颇,如果有幸有大佬看到这篇文章,希望能给予批评指正. 导航 (一) 入门例子 (二) 测试用例 ...
- CSS | 圣杯布局、双飞翼布局 | 自适应三栏布局
圣杯布局和双飞翼布局是前端工程师需要日常掌握的重要布局方式.两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局 虽然两者的实现方法略有差异,不过都遵循了以下要点: 1.两侧宽度固定 ...
- Spring Boot微服务电商项目开发实战 --- 分布式开发要避的那些坑
今天已经进入第七讲了,整个微服务架构的搭建工作也基本完成.那到目前为止究竟使用了那些技术及实现了什么功能呢?我们先回顾一下. 使用的技术:SpringBoot.Dubbo.Zookeeper.Redi ...
- 63-容器在 Weave 中如何通信和隔离?
上一节我们分析了 Weave 的网络结构,今天讨论 Weave 的连通和隔离特性. 首先在host2 执行如下命令: weave launch 192.168.0.44 这里必须指定 host1 的 ...
- linux 常用Mysql脚本命令
常用命令 无需系统Root权限 新数据库设置Root密码 visible > mysql -uroot -p visible > mysqladmin -uroot password &q ...
- Git常用进阶操作之一
提起Git,经常做项目的我们都不陌生,我们常用的功能有哪些呢? 这里按个人使用情况简单总结一下. 像新建远程仓库.新建分支这些就不说了,不熟的同学可以翻看我前面写的git基本操作. 1.首先提一下为每 ...
- js实现弹出框跟随鼠标移动
又是新的一天网上冲浪,在bing的搜索页面下看到这样一个效果: 即弹出框随着鼠标的移动而移动.思路大概为: 调用onmousemove函数,将鼠标的当前位置赋予弹出框即可 //html <div ...