Codeforces Round 936 E. Girl Permutation(分治、组合计数)

E. Girl Permutation

1
2

题意

有一个位置的长度为 n n n排列 ,现在给定一个前缀最值下标数组 p p p 和一个后缀最值下标数组 s s s

  • 在位置 i i i 的前缀最值下标定义为:以 i i i结尾的前缀,最大值恰好在 i i i,也就是 ∀ j < i , a j < a i \forall j < i,a_j < a_i j<iaj<ai,如果不满足条件,那么 i i i 不出现在 p p p

后缀最值下标也是类似

现在求出符合 p p p s s s 的排列个数,对 1 e 9 + 7 1e9 + 7 1e9+7 求模

思路

首先不难观察到:最大值 n n n 所在的下标一定会出现在 p [ m 1 − 1 ] p[m1-1] p[m11] s [ 0 ] s[0] s[0],并且 p [ 0 ] = 1 p[0] = 1 p[0]=1 s [ m 2 − 1 ] = n s[m2 - 1] = n s[m21]=n,如果不满足这些条件,就不存在任何一个满足条件的排列

否则,我们可以唯一确定 n n n 的位置,就是在 p [ m 1 − 1 ] p[m1 - 1] p[m11],那么我们需要从 n − 1 n - 1 n1(最大值 n n n 已被分配)个数中,选择 p [ m 1 − 1 ] − 1 p[m1 - 1] - 1 p[m11]1 个数到左半部分,剩下的数在右半部分,这里的方案数是 ( n − 1 p m 1 − 1 − 1 ) \binom{n - 1}{p_{m_1-1} - 1} (pm111n1),然后我们继续对于 p [ m 1 − 2 ] p[m1-2] p[m12] 考虑,可以发现,这个位置是 [ 1 , p m 1 − 1 − 1 ] [1,p_{m_1-1}-1] [1,pm111] 这个前缀的最大值,也就是我们前面分配过来的那些数的最大值!

想到这里,我们就可以考虑分治来求解方案数了,对于当前的一个左半部份,其最大值在 p [ i ] p[i] p[i],那么表示的是前缀 [ 1 , p [ i + 1 ] − 1 ] [1, p[i + 1] - 1] [1,p[i+1]1] 这个子状态,我们继续从 p [ i + 1 ] − 2 p[i + 1] - 2 p[i+1]2 个数(两个数已经在 p [ i ] p[i] p[i] p [ i + 1 ] p[i + 1] p[i+1])中选择 p [ i ] − 1 p[i] - 1 p[i]1 个数到 p [ i ] p[i] p[i] 的左边,其余留在 [ p [ i ] + 1 , p [ i + 1 ] − 1 ] [p[i] + 1, p[i + 1] - 1] [p[i]+1,p[i+1]1],这里贡献的方案数是 ( p i + 1 − 2 p i − 1 ) \binom{p_{i + 1} - 2}{p_i - 1} (pi1pi+12),注意这里还要考虑留在 [ p [ i ] + 1 , p [ i + 1 ] − 1 ] [p[i] + 1, p[i + 1] - 1] [p[i]+1,p[i+1]1] 的部分,这里的数字可以 任意排列 ,因此我们要乘上阶乘 ( p i + 1 − p i − 1 ) ! (p_{i + 1} - p_i - 1)! (pi+1pi1)!

对于右半部分,也是类似的计算方法

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;const int INF=0x3f3f3f3f;
const long long INFLL=1e18;typedef long long ll;template<class T>
constexpr T power(T a, ll b){T res = 1;while(b){if(b&1) res = res * a;a = a * a;b >>= 1;}return res;
}constexpr ll mul(ll a,ll b,ll mod){ //快速乘,避免两个long long相乘取模溢出ll res = a * b - ll(1.L * a * b / mod) * mod;res %= mod;if(res < 0) res += mod; //误差return res;
}template<ll P>
struct MLL{ll x;constexpr MLL() = default;constexpr MLL(ll x) : x(norm(x % getMod())) {}static ll Mod;constexpr static ll getMod(){if(P > 0) return P;return Mod;}constexpr static void setMod(int _Mod){Mod = _Mod;}constexpr ll norm(ll x) const{if(x < 0){x += getMod();}if(x >= getMod()){x -= getMod();}return x;}constexpr ll val() const{return x;}explicit constexpr operator ll() const{ return x; //将结构体显示转换为ll类型: ll res = static_cast<ll>(OBJ)}constexpr MLL operator -() const{ //负号,等价于加上ModMLL res;res.x = norm(getMod() - x);return res;}constexpr MLL inv() const{assert(x != 0);return power(*this, getMod() - 2); //用费马小定理求逆}constexpr MLL& operator *= (MLL rhs) & { //& 表示“this”指针不能指向一个临时对象或const对象x = mul(x, rhs.x, getMod()); //该函数只能被一个左值调用return *this;}constexpr MLL& operator += (MLL rhs) & {x = norm(x + rhs.x);return *this;}constexpr MLL& operator -= (MLL rhs) & {x = norm(x - rhs.x);return *this;}constexpr MLL& operator /= (MLL rhs) & {return *this *= rhs.inv();}friend constexpr MLL operator * (MLL lhs, MLL rhs){MLL res = lhs;res *= rhs;return res;}friend constexpr MLL operator + (MLL lhs, MLL rhs){MLL res = lhs;res += rhs;return res;}friend constexpr MLL operator - (MLL lhs, MLL rhs){MLL res = lhs;res -= rhs;return res;}friend constexpr MLL operator / (MLL lhs, MLL rhs){MLL res = lhs;res /= rhs;return res;}friend constexpr std::istream& operator >> (std::istream& is, MLL& a){ll v;is >> v;a = MLL(v);return is;}friend constexpr std::ostream& operator << (std::ostream& os, MLL& a){return os << a.val();}friend constexpr bool operator == (MLL lhs, MLL rhs){return lhs.val() == rhs.val();}friend constexpr bool operator != (MLL lhs, MLL rhs){return lhs.val() != rhs.val();}
};const ll mod = 1e9 + 7;
using Z = MLL<mod>;struct Comb {int n;std::vector<Z> _fac;std::vector<Z> _invfac;std::vector<Z> _inv;Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}Comb(int n) : Comb() {init(n);}void init(int m) {m = std::min(1ll * m, Z::getMod() - 1);if (m <= n) return; //已经处理完了需要的长度_fac.resize(m + 1);_invfac.resize(m + 1);_inv.resize(m + 1);for (int i = n + 1; i <= m; i++) {_fac[i] = _fac[i - 1] * i;}_invfac[m] = _fac[m].inv();for (int i = m; i > n; i--) { //线性递推逆元和阶乘逆元_invfac[i - 1] = _invfac[i] * i;_inv[i] = _invfac[i] * _fac[i - 1];}n = m; //新的长度}Z fac(int m) {if (m > n) init(2 * m);return _fac[m];}Z invfac(int m) {if (m > n) init(2 * m);return _invfac[m];}Z inv(int m) {if (m > n) init(2 * m);return _inv[m];}Z binom(int n, int m) { //二项式系数if (n < m || m < 0) return 0;return fac(n) * invfac(m) * invfac(n - m);}
} comb;int main(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);int t;std::cin >> t;while(t--) {int n, m1, m2;std::cin >> n >> m1 >> m2;std::vector<int> p(m1), s(m2);fore(i, 0, m1) std::cin >> p[i];fore(i, 0, m2) std::cin >> s[i];if(p[0] != 1 || p[m1 - 1] != s[0] || s[m2 - 1] != n){std::cout << "0\n";continue;}Z ans = comb.binom(n - 1, p[m1 - 1] - 1);for(int i = m1 - 2; i >= 0; --i) ans *= comb.binom(p[i + 1] - 2, p[i] - 1) * comb.fac(p[i + 1] - p[i] - 1);fore(i, 1, m2) ans *= comb.binom(n - s[i - 1] - 1, n - s[i]) * comb.fac(s[i] - s[i - 1] - 1);std::cout << ans << endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/578159.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验室开放项目实验报告-01

实验室开放项目实验报告 实验名称&#xff1a;实验一输入输出格式 实验目的&#xff1a;熟练掌握程序设计竞赛中通常采用的输入输出格式和掌握不同格式输入输出数据的处理方法 实验内容&#xff1a; 在本地电脑中新建一个文件夹&#xff0c;用于存放C源程序&#xff0c;文件…

【动手学深度学习-pytorch】8.5 循环神经网络的从零开始实现

转换输入的维度&#xff0c; 以获得形状为&#xff08;时间步数&#xff0c;批量大小&#xff0c;词表大小&#xff09;的输出&#xff0c;这将使我们能够更方便地通过最外层的维度&#xff0c; 一步一步地更新小批量数据的隐状态。 >当训练语言模型时&#xff0c;输入和输出…

北京WordPress建站公司

北京wordpress建站&#xff0c;就找北京wordpress建站公司 http://wordpress.zhanyes.com/beijing

C#OpenCvSharp YOLO v3 Demo

目录 效果 项目 代码 下载 效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp; using S…

SiameseRPN原理详解(个人学习笔记)

参考资源&#xff1a; 视觉目标跟踪SiamRPNSiameseRPN详解CVPR2018视觉目标跟踪之 SiameseRPN 目录&#xff09; 1. 模型架构1.1 Siamese Network1.2 RPN 2. 模型训练2.1 损失函数2.2 端到端训练2.3 正负样本选择 3. 跟踪阶段总结 SiamRPN是在SiamFC的基础上进行改进而得到的一…

产品推荐 | 基于华为海思ARM+Xilinx FPGA双核的8路SDI高清视频图像处理平台

一、板卡概述 PCIE703 是我司自主研制的一款基于 PCIE 总线架构的高性能综 合视频图像处理平台&#xff0c;该平台采用 Xilinx 的高性能 Kintex UltraScale 系列 FPGA 加上华为海思的高性能视频处理器来实现。 华为海思的 HI3531DV200 是一款集成了 ARM A53 四核处理 器性能强…

003 高并发内存池_整体框架设计

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;高并发内存池 &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言一、ThreadCache整体框架设计二、CentralCache整体框架设计三、PageCache整体框架设计 小结 前言 在…

个人简历主页搭建系列-05:部署至 Github

前面只是本地成功部署网站&#xff0c;网站运行的时候我们可以通过 localhost: port 进行访问。不过其他人是无法访问我们本机部署的网站的。 接下来通过 Github Pages 服务把网站部署上去&#xff0c;这样大家都可以通过特定域名访问我的网站了&#xff01; 创建要部署的仓库…

U盘文件突然消失?原因与恢复策略全解析

一、遭遇不测&#xff1a;U盘文件突然消失 在日常生活和工作中&#xff0c;U盘扮演着不可或缺的角色&#xff0c;它小巧便捷&#xff0c;能够随时随地存储和传输文件。然而&#xff0c;有时我们会遭遇一个令人头疼的问题&#xff1a;U盘中的文件突然消失。这种突如其来的变故往…

Web漏洞-深入WAF注入绕过

目录 简要其他测试绕过 方式一:白名单&#xff08;实战中意义不大&#xff09; 方式二:静态资源 方式三: url白名单 方式四:爬虫白名单 #阿里云盾防SQL注入简要分析 #安全狗云盾SQL注入插件脚本编写 在攻防实战中&#xff0c;往往需要掌握一些特性&#xff0c;比如服务…

Linux CPU 占用率 100% 排查

Linux CPU 占用率 100% 排查 总体来说分为五个步骤 top 命令定位应用进程 pidtop -Hp [pid] 定位应用进程对应的线程 tidprintf “%x\n” [tid] 将 tid 转换为十六进制jstack [pid] | grep -A 10 [tid 的十六进制] 打印堆栈信息根据堆栈信息分析问题 以下为实战例子 写一段…

SQLBolt,一个练习SQL的宝藏网站

知乎上有人问学SQL有什么好的网站&#xff0c;这可太多了。 我之前学习SQL买了本SQL学习指南&#xff0c;把语法从头到尾看了个遍&#xff0c;但仅仅是心里有数的程度&#xff0c;后来进公司大量的写代码跑数&#xff0c;才算真真摸透了SQL&#xff0c;知道怎么调优才能最大化…