[2021-09-09 T2] 就差⼀点——冒泡排序和反序表之间不为人知的秘密

就差一点解题报告

  • description
  • solution
  • code

description

题目描述

冒泡排序是⼀个简单的排序算法,其时间复杂度为O(n2)O(n^2)O(n2)

有⼀个大小为nnn的排列p1,...,pnp_1,...,p_np1,...,pn,⼩明想对这个排列进⾏冒泡排序,于是写了下⾯这份代码:

for(int i=1;i<=k;i++)for(int j=1;j<n;j++)if(p[j]>p[j+1]) swap(p[j],p[j+1]);

细⼼的选手不难发现小明手抖把第⼀行中的nnn打成了kkk,所以当kkk比较小时,这份代码可能会出错

⼩明发现当这份代码出错时,可能就差⼀点就能把这个排列排序,他定义⼀个排列就差⼀点能被排序,当且仅当这个排列存在⼀个大小为n−1n-1n1的上升子序列

小明想知道,对于给定的n,kn,kn,k,有多少种不同的排列满⾜对这个排列运⾏上述代码后,这个排列就差⼀点能被排序

由于答案可能很⼤,⼩明只需要知道答案对质数modmodmod取模的结果

输入格式

本题⼀个测试点含有多组测试数据,第⼀行⼀个整数TTT,表示数据组数

接下来TTT行,每行333个整数,n,k,modn,k,modn,k,mod,意义同题意

输出格式

TTT行,对于每组测试数据,输出一行一个整数表示答案

样例

5
5 1 998244353
5 2 998244353
5 3 998244353
5 4 998244353
5 5 998244353
74
114
120
120
120

数据范围

1≤n,k,T≤5000,108≤mod≤109+71\le n,k,T\le5000,10^8\le mod\le 10^9+71n,k,T5000,108mod109+7

solution

  • DDG有个神奇DPDPDP,正确倒是正确,只是这是怎么想到的呢?

    dpi,j=∑k=1j−1dpi−1,k+j∗dpi,jdp_{i,j}=\sum_{k=1}^{j-1}dp_{i-1,k}+j*dp_{i,j}dpi,j=k=1j1dpi1,k+jdpi,j (前iii个数,在xxx前面比xxx大的数的个数最大值为jjj 的序列)

    因为一次冒泡排序,相当于处理了 在iii前面比iii大的数个数最多 的iii

  • 卷爷找了三个强大的性质

    最重要的性质就是,对于属于[i,n][i,n][i,n]的所有下标,将这些下标抽出来,然后根据值离散化

    如果离散化后的序列需要ttt次变成单调上升,那么回到原序列,也只需要ttt次,单看这些下标,就会发现是单调上升的


结合这两种思路,就来到了小儿子的通俗易懂的解法——反序表

反序表对于一个排列的定义为si=∑j=1i−1[pj>pi]s_i=\sum_{j=1}^{i-1}[p_j>p_i]si=j=1i1[pj>pi]

  • 即反序表的第iii位上的数值表示:在原排列中,第iii位以前的比第iii位值大的个数

e.g. 原序列3 2 4 1 5,反序表为0 1 0 3 0

反序表具有很多非常好的性质

  • 显然对于iiisi<is_i<isi<i严格小于);换言之,对于iii,其sis_isi的取值为[0,i)[0,i)[0,i)iii

  • 反序表与排列是一一对应的,那么原题要求排列个数,就转化成了求反序表的个数

  • 冒泡一轮排序会将 最大的 还没在应在位置的值 放置在 其应在位置,然后这区间中的每个数位置都会前移一位,其在反序表的变化则为下标,值均减一(如果已经是000就不减)

    换言之,一次冒泡排序后,每个数至多只会减少一

    e.g.

    原序列3 2 5 1 4,反序表为0 1 0 3 1

    一次冒泡排序后

    原序列3 2 1 4 5,反序表为0 1 2 0 0

    555由位置333变到555,反序表改变的区间为[3,5][3,5][3,5]

  • 反序表中iii位置上的值如果为sis_isi,意味着至少需要sis_isi次冒泡排序才能将原序列iii有序

    这里的有序定义为,其前面的数全小于ta,其后面的数全大于ta


了解完反序表的性质后,就可以解决这道题了

  • 考虑冒泡排序后,最后的序列是一个长为nnn的上升子序列(不差一点)

    这时的反序表全是0000,0,0,...,0

    一次排序,反序表只能减一或者不减,kkk次排序最多减少kkk

    也就是说想要最后反序表为000,其初始值不能超过kkk

    即:∀isi≤min⁡(i−1,k)\forall_i\quad s_i\le \min(i-1,k)isimin(i1,k)

    将这些值域限制乘起来就是不同的反序表个数,也就是不同的排列个数

    即:∏i=1n(min⁡(i−1,k)+1)\prod_{i=1}^n\Big(\min(i-1,k)+1\Big)i=1n(min(i1,k)+1)

  • 考虑冒泡排序后,最后的序列是一个长为n−1n-1n1的上升子序列(只差一点)

    • 这时的反序表形如0,0,...,1,1,...,1,0,0,...,0

      e.g. 最后序列为4 1 2 3 5,反序表为0 1 1 1 0

      最后为000说明初始反序表的值不超过kkk

      最后为111说明初始反序表的值不超过k+1k+1k+1

      注意:sis_isi能取到k+1k+1k+1iii是有限制的,仅为[k+2,n][k+2,n][k+2,n],共n−(k+2)+1=n−k−1n-(k+2)+1=n-k-1n(k+2)+1=nk1

      (不要忘记si<is_i<isi<i的约束)

      考虑枚举这段111的长度lenlenlen

      这段长度的选择方案相当于在总长为n−k−1n-k-1nk1中摆下lenlenlen的放置方案,显然为n−k−1−len+1=n−k−lenn-k-1-len+1=n-k-lennk1len+1=nklen

      剩下的n−k−1−lenn-k-1-lennk1len个数反序表都不超过kkk,可选为[0,k][0,k][0,k]k+1k+1k+1

      这些数生成的反序表组合为(k+1)n−k−1−len(k+1)^{n-k-1-len}(k+1)nk1len,再乘上前kkk个数的组合

      即:(k+1)!∗∑i=1n−k−1(k+1)n−k−1−len∗(n−k−len)(k+1)!*\sum_{i=1}^{n-k-1}(k+1)^{n-k-1-len}*(n-k-len)(k+1)!i=1nk1(k+1)nk1len(nklen)

    • 这时的反序表有且仅有一个位置,其si>1s_i>1si>1(严格大于)

      e.g. 最后序列为2 3 1 4 5,反序表为0 0 2 0 0

      相当于原始si>k+1s_i>k+1si>k+1,这个iii同样有范围限制,为[k+3,n][k+3,n][k+3,n]

      对于iii其选择方案为i−1−(k+2)+1=i−k−2i-1-(k+2)+1=i-k-2i1(k+2)+1=ik2

      即:∑i=k+3n∏j=1n[j≠i](min⁡(j−1,k)+1)⋅[j=i](i−k−1)\sum_{i=k+3}^n\prod_{j=1}^n[j≠i]\big(\min(j-1,k)+1\big)·[j=i](i-k-1)i=k+3nj=1n[j=i](min(j1,k)+1)[j=i](ik1)

code

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 5005
#define int long long
int T, n, k, mod, fac;
int inv[maxn], mi[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld %lld", &n, &k, &mod );fac = inv[1] = mi[0] = 1;if( k >= n ) {for( int i = 1;i <= n;i ++ )fac = fac * i % mod;printf( "%lld\n", fac );continue;}for( int i = 1;i <= k + 1;i ++ )fac = fac * i % mod;for( int i = 2;i <= k + 1;i ++ )inv[i] = ( mod - mod / i ) * inv[mod % i] % mod;for( int i = 1;i <= n;i ++ ) mi[i] = mi[i - 1] * ( k + 1 ) % mod;int ans = fac * mi[n - k - 1] % mod;for( int i = 1;i <= n - k - 1;i ++ )ans = ( ans + fac * ( n - k - i ) % mod * mi[n - k - 1 - i] ) % mod;int mul = 1;for( int i = 1;i <= n;i ++ )mul = mul * ( min( i - 1, k ) + 1 ) % mod;for( int i = k + 3;i <= n;i ++ )ans = ( ans + mul * inv[min( i - 1, k ) + 1] % mod * ( i - k - 2 ) ) % mod;printf( "%lld\n", ans );}return 0;
}

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

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

相关文章

CodeForces - 76E Points

CodeForces - 76E Points 题意&#xff1a; 给你n个点的坐标&#xff0c;求所有一对点之间的距离的平方和 n<100000 题解&#xff1a; 直接暴力n2肯定不行&#xff0c;我们把这个的式子列出来&#xff1a; 代码&#xff1a; #include<bits/stdc.h> #define deb…

模板:Miller-RabinPollard-Rho(数论)

所谓 pollard-rho&#xff0c;就是泼辣的肉 &#xff08;逃&#xff09; 前言 许多题解都把这两个算法放在了一起。 那我也这样办吧&#xff01; miller-rabin可以在优秀的时间复杂度内完成对一个数的素性检测。 而pollard-rho则是立足于Miler-rabin之上&#xff0c;可以在 …

Asp.NetCore轻松学-部署到 Linux 进行托管

前言上一篇文章介绍了如何将开发好的 Asp.Net Core 应用程序部署到 IIS&#xff0c;且学习了进程内托管和进程外托管的区别&#xff1b;接下来就要说说应用 Asp.Net Core 的特性&#xff08;跨平台&#xff09;&#xff0c;将 .NetCore 部署到 Linux 中&#xff0c;主流的 Linu…

DevC++ 用C语言的多线程 实现简单的客户端和服务器

知识来源一&#xff1a; 使用Dev-C实现简单的客户端和服务器-CSDN博客 此先生的博客使用的是win32 SDK来创建多线程&#xff0c;然后鄙人对这个版本的多线程细节不明。于是又重新用C语言的线程替代win32API,以此继续学习服务器代码。 知识来源二&#xff1a;DevC 多线程创建…

[2021-09-09 T3] 序列/luogu P3943 星空(异或差分+bfs最短路+状压dp)

序列descriptionsolutioncodedescription 题目描述 长度为nnn的序列&#xff0c;初始全为000&#xff0c;每次可以选择⼀个数ai(1≤i≤l)a_i(1\le i\le l)ai​(1≤i≤l)&#xff0c;然后选择连续aia_iai​个元素异或上111 求最少的次数&#xff0c;使得对于所有i(1≤i≤k)i(…

HDU - 4608 I-number

题意&#xff1a; 给你一个x&#xff0c;让你构造一个y&#xff0c;y的要求&#xff1a; y>xy的各项之和为10的倍数在满足前两个的前提下&#xff0c;y尽可能小 题解&#xff1a; 模拟&#xff0c;尽可能的模拟&#xff0c;用字符串模拟 先将各位相加得到sum&#xff0c…

从初创公司的角度来看微服务

在开展微服务的过程中&#xff0c;了解要考虑哪些因素可能是非常有挑战性的事情。没有可以直接使用的金科玉律。每个过程都是不同的&#xff0c;因为每个组织面临的都是不同的环境。在本文中&#xff0c;我将从初创公司的角度分享我们学习到的经验和面临的挑战&#xff0c;以及…

洛谷P2056:[ZJOI2007]捉迷藏(点分树、STL)

解析 见到动态维护最远点对&#xff0c;不难想到利用 set 维护最大值和次大值&#xff0c;每个点维护两个 set 的杂技做法。 但是问题是…T了啊。 咋办嘞。 一个在本题至关重要的 trick&#xff1a;利用两个堆来支持访问最大值和删除 具体也很好理解&#xff1a;当删除的时候…

[NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

[NOI2018] 归程descriptionsolution1code1solution2codedescription 题目描述 本题的故事发生在魔力之都&#xff0c;在这里我们将为你介绍一些必要的设定 魔力之都可以抽象成一个nnn个节点、mmm条边的无向连通图&#xff08;节点的编号从111至nnn&#xff09;我们依次用 l,…

CodeForces - 616D Longest k-Good Segment

CodeForces - 616D Longest k-Good Segment 题意&#xff1a; 有包含n个数的序列a&#xff0c;求能找到最长的区间包含不超过k个不同的元素。 题解&#xff1a; 尺取法&#xff0c;先固定L&#xff0c;然后移动R&#xff0c;R每次移动&#xff0c;当超过k后&#xff0c;L再…

MySQL 集群方案介绍

mysql集群方案这里介绍2种&#xff0c;PXC 和 Replication。大型互联网程序用户群体庞大&#xff0c;所以架构设计单节点数据库已经无法满足需求。大家也深有体会&#xff0c;有一万人在学校网站查成绩或是选课的时候网站时常是访问不了或者相应特别特别慢。这种情况就凸显出来…

模板:回文自动机(PAM)

所谓回文自动机&#xff0c;就是关于回文的自动机。 &#xff08;逃&#xff09; 前言 小清新自动机。 经历过SAM的大风大浪&#xff0c;这个相比而言好理解多了&#xff0c;感觉也许应该先学这个再学SAM… 解析 和trie、AC自动机、SAM等类似的&#xff0c;PAM的每个结点表…

Gym - 215177C 玩游戏

题意&#xff1a; ljcc和他的学妹在玩游戏&#xff0c;这个游戏共有 n 轮&#xff0c;在第 i 轮获胜会获得 i 分&#xff0c;没有平局。 现在给出ljcc和学妹的得分&#xff0c;求是否有一种方案符合当前得分。 题解&#xff1a; 第i轮得到i分&#xff0c;一共n轮&#xff0…

Zju2112 Dynamic Rankings(树状数组套可持久化权值线段树)

Zju2112 Dynamic Rankingsdescriptionsolutioncodedescription 给定一个含有n个数的序列a[1],a[2],a[3]……a[n]&#xff0c;程序必须回答这样的询问&#xff1a;对于给定的i,j,k&#xff0c;在a[i],a[i1 ],a[i2]……a[j]中第k小的数是多少(1≤k≤j-i1)&#xff0c;并且&…

ML.NET案例详解:在.NET下使用机器学习API实现化学分子式数据格式的判定

半年前写过一篇类似的文章&#xff0c;题目是&#xff1a;《在.NET中使用机器学习API&#xff08;ML.NET&#xff09;实现化学分子式数据格式的判定》&#xff0c;在该文中&#xff0c;我介绍了化学分子式数据格式的基本知识&#xff0c;同时给出了一个案例&#xff0c;展示了如…

洛谷P4762: [CERC2014]Virus synthesis(PAM)

解析 自己对PAM的理解不够深刻。 最优方案必然是先选择一个偶回文串&#xff0c;递归构造出它的一半。花一步逆序&#xff0c;然后暴力解决剩下的。 这似乎已经依稀出现了某种dp的思路。 考虑如何更好的转移。设计 transxtrans_xtransx​ 表示长度不超过 xxx 一半的最长回文后…

Triangle HDU - 5914

Triangle HDU - 5914 题意&#xff1a; 有长度分别是1到n的n给木棍&#xff0c;问最少拿走几个木棍&#xff0c;使得剩下木棍无法组成三角形 题解&#xff1a; 组不成三角形的恰巧情况就是ab<c&#xff0c;也就是我们要让剩下的木棍&#xff0c;两者之和等于或小于第三个…

CodeForces - 336A Vasily the Bear and Triangle

CodeForces - 336A Vasily the Bear and Triangle 题意&#xff1a; 给你一个点x&#xff0c;现在这个点和原点组成了矩形&#xff0c;让你在x和y轴分别求一个点&#xff0c;与原点构成的三角形&#xff0c;要求矩形在三角形内&#xff0c;点x在斜边上 题解&#xff1a; 这…

数据结构之线段树合并——永无乡,Lomsat gelral,Tree Rotations,Tree Rotations Escape Through Leaf

文章目录[HNOI2012]永无乡Lomsat gelral「POI2011 R2 Day2」旋转树木 Tree RotationsEscape Through Leaf线段树合并与 fhq-treap合并很类似&#xff0c;也是将两个不同根的线段树暴力合并至于时间复杂度&#xff0c;线段树合并一次是可以达到O(n)O(n)O(n)的&#xff0c;但是大…

吉特仓储管理系统--开源2018年源码

应该说今天过完&#xff0c;这个年就算真正意义上的过完了&#xff0c;没有想到的是又是在出差的路上写这样的文章。废话也不多说&#xff0c;写这篇文章主要的目的是想将去年吉特仓储管理系统开发的一个版本源代码开放出来&#xff0c;供各位开发者阅读使用。github 源代码地址…