NOIP2023模拟5联测26 零二

2023-10-30 03:36
文章标签 模拟 26 联测 noip2023 零二

本文主要是介绍NOIP2023模拟5联测26 零二,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意

有一个长度为 n n n的序列 A A A,你可以将 A A A中的元素进行重排得到一个新的序列 B B B,规则如下:

  • B B B初始为空,同时维护一个初始为空的小根堆 T T T,然后进行以下两类操作各 n n n次:
    • 将当前 A A A的第一个元素删除并加入小根堆 T T T
    • 将小根堆的堆顶删除并加入 B B B的末尾,需要保证 T T T非空

操作的顺序是任意的,问总共可能得到多少种不同的 B B B,输出答案模 1 0 9 + 7 10^9+7 109+7后的值。

1 ≤ n ≤ 100 , 1 ≤ A i ≤ n 1\leq n\leq 100,1\leq A_i\leq n 1n100,1Ain


题解

注意到 1 ≤ a i ≤ n 1\leq a_i\leq n 1ain,我们先考虑如果 A i A_i Ai 1 1 1 n n n的一个排列该怎么求解。

我们设 n n n A A A序列和 B B B序列中出现的位置分别为 p , q p,q p,q,即 A p = B q = n A_p=B_q=n Ap=Bq=n。因为 T T T是小根堆,且 A A A 1 1 1 n n n的一个排列,所以当拿出 n n n时就意味着 T T T已经被搬空了。由此可得, B B B的前 q q q个元素就是 A A A的前 q q q个元素,只是顺序可能不太一样。所以, { A 1 , A 2 , … , A q } = { B 1 , B 2 , … , B q } \{A_1,A_2,\dots,A_q\}=\{B_1,B_2,\dots,B_q\} {A1,A2,,Aq}={B1,B2,,Bq},且 { A q + 1 , A q + 2 , … , A n } = { B q + 1 , B q + 2 , … , B n } \{A_{q+1},A_{q+2},\dots,A_n\}=\{B_{q+1},B_{q+2},\dots,B_n\} {Aq+1,Aq+2,,An}={Bq+1,Bq+2,,Bn}

既然我们已经知道 B q = n B_q=n Bq=n,那么我们可以把原问题看作两个子问题: [ 1 , q − 1 ] [1,q-1] [1,q1] [ q + 1 , n ] [q+1,n] [q+1,n]。其中 B 1 , B 2 , … , B q − 1 B_1,B_2,\dots,B_{q-1} B1,B2,,Bq1是由 A 1 , A 2 , … , A q A_1,A_2,\dots,A_q A1,A2,,Aq去掉 A p A_p Ap再经过一些操作变化而来的,而 B q + 1 , B q + 2 , … , B n B_{q+1},B_{q+2},\dots,B_n Bq+1,Bq+2,,Bn是由 A q + 1 , A q + 2 , … , A n A_{q+1},A_{q+2},\dots,A_n Aq+1,Aq+2,,An经过一些操作变化而来的。

我们考虑递归地解决子问题。

因为在每次将一个问题分为子问题时都是将一个最大值删去,再分成两个部分,那么每个子问题所对应的子序列 A ′ A' A都是原序列 A A A的某一段区间 [ l , r ] [l,r] [l,r]删去一些较大的数而得到的。

我们考虑 D P DP DP,设 f l , r , i f_{l,r,i} fl,r,i表示 A l , A l + 1 , … , A r A_l,A_{l+1},\dots,A_r Al,Al+1,,Ar中不超过 i i i的数构成的子序列的方案数。设 A m = i A_m=i Am=i,下面考虑转移:

  • m m m不在 [ l , r ] [l,r] [l,r]上时,显然 f l , r , i = f l , r , i − 1 f_{l,r,i}=f_{l,r,i-1} fl,r,i=fl,r,i1
  • m m m [ l , r ] [l,r] [l,r]上时,我们枚举 i i i B B B中的位置,可得
    f l , r , i = ∑ x = m r f l , x , i − 1 ⋅ f x + 1 , r , i − 1 f_{l,r,i}=\sum\limits_{x=m}^rf_{l,x,i-1}\cdot f_{x+1,r,i-1} fl,r,i=x=mrfl,x,i1fx+1,r,i1

那我们再来考虑如何处理 A A A不是 1 1 1 n n n的排列的情况。

我们约定,当小根堆的堆顶为 i i i,并且堆中存在多个 i i i,那么我们取的时候先取下标最小的。

那在我们的约定下,可以将原数列转化为一个排列。

考虑这样转化的正确性。转化后 A A A中的数和 B B B中的数一一对应,而且 B B B中相同的数的先后顺序和在 A A A中的先后顺序是相同的,也就是说先后顺序一定,所以这样转化是可行的。

时间复杂度为 O ( n 4 ) O(n^4) O(n4),这跑不满,是可以过的。

code

#include<bits/stdc++.h>
using namespace std;
const int N=100;
const long long mod=1e9+7;
int n,a[N+5],b[N+5],cnt[N+5],rk[N+5];
long long f[N+5][N+5][N+5];
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);++cnt[a[i]];}for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];for(int i=n;i>=1;i--){b[i]=cnt[a[i]]--;rk[b[i]]=i;}for(int i=1;i<=n+1;i++){for(int j=0;j<=n+1;j++) f[i][i-1][j]=1;}for(int l=n;l>=1;l--){for(int r=l;r<=n;r++){f[l][r][0]=1;if(b[l]<b[r])for(int i=1;i<b[r];i++) f[l][r][i]=f[l][r-1][i];elsefor(int i=1;i<b[l];i++) f[l][r][i]=f[l+1][r][i];for(int i=max(b[l],b[r]);i<=n;i++){if(rk[i]<l||rk[i]>r) f[l][r][i]=f[l][r][i-1];else{for(int j=rk[i];j<=r;j++){if(b[j]<=i)f[l][r][i]=(f[l][r][i]+f[l][j][i-1]*f[j+1][r][i-1])%mod;}}}}}printf("%lld",f[1][n][n]);return 0;
}

这篇关于NOIP2023模拟5联测26 零二的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/305335

相关文章

Linux下MySQL8.0.26安装教程

《Linux下MySQL8.0.26安装教程》文章详细介绍了如何在Linux系统上安装和配置MySQL,包括下载、解压、安装依赖、启动服务、获取默认密码、设置密码、支持远程登录以及创建表,感兴趣的朋友... 目录1.找到官网下载位置1.访问mysql存档2.下载社区版3.百度网盘中2.linux安装配置1.

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

hdu4431麻将模拟

给13张牌。问增加哪些牌可以胡牌。 胡牌有以下几种情况: 1、一个对子 + 4组 3个相同的牌或者顺子。 2、7个不同的对子。 3、13幺 贪心的思想: 对于某张牌>=3个,先减去3个相同,再组合顺子。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOExcepti

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

【算法专场】模拟(下)

目录 前言 38. 外观数列 算法分析 算法思路 算法代码 1419. 数青蛙 算法分析 算法思路 算法代码  2671. 频率跟踪器 算法分析 算法思路 算法代码 前言 在前面我们已经讲解了什么是模拟算法,这篇主要是讲解在leetcode上遇到的一些模拟题目~ 38. 外观数列 算法分析 这道题其实就是要将连续且相同的字符替换成字符重复的次数+

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x){if (_finish == _endofstorage){int n = pos - _start;size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//防止迭代

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1:输入:a = "11", b = "1"输出:"100"示例 2:输入:a = "1010", b = "1011"输出:"10101" 算法设计 可以从低位到高位(从后向前)计算,用一个变量carry记录进位,如果有字符没处理完或者有进位,则循环处理。两个字符串对