当前位置: 首页 > news >正文

【学习笔记】「NOI2018」冒泡排序

从题解的角度来说,这是一道简单题。不过考场上在没有任何人提示的情况下要想出正确的结论其实并不容易。

我自己做这道题的时候,因为没有想清楚题目给出的下界能取到的充要条件是什么,所以到了很晚才猜到结论,以至于难以为继。

结论:当且仅当一个排列不含有长度为333的下降子序列,冒泡排序的交换次数取到下界。这也非常好理解,因为如果一个位置存在前面一个数比它大,后面一个数比它小,那么至少会向左/向右移动一次,因此取不到下界。

证明需要运用Dilworth\text{Dilworth}Dilworth定理,我们可以把原序列划分成两个上升子序列 ,其中一个子序列的数只会往左移,另一个子序列的数只会往右移,然后就证完了。

先不考虑字典序的限制。我们将限制转化一下,变成不存在一个位置iii,使得存在前面的一个数比它大,后面的一个数比它小。这直接导出了下面的dpdpdp:设dpi,jdp_{i,j}dpi,j表示前iii个位置,最大值为jjj的方案数。如果[1:i−1][1:i-1][1:i1]的最大值为jjj,那么pip_ipi只能是[1:j][1:j][1:j]中没填的最小的那一个,方案数dpi−1,jdp_{i-1,j}dpi1,j。否则,若[1:i−1][1:i-1][1:i1]最大值为k(k<j)k(k<j)k(k<j),那么pip_ipijjj总是合法的。那么,dpi,j=∑k≤jdpi−1,k(i≤j)dp_{i,j}=\sum_{k\le j}dp_{i-1,k}(i\le j)dpi,j=kjdpi1,k(ij) 。我们发现这就是从(1,1)(1,1)(1,1)走到(n,n)(n,n)(n,n)且不穿过对角线x=yx=yx=y的方案数,也就是(2nn)−(2nn−1)\binom{2n}{n}-\binom{2n}{n-1}(n2n)(n12n)

回到原题,我们枚举lcp\text{lcp}lcp,然后就变成了求从(i,j)(i,j)(i,j)走到(n,n)(n,n)(n,n)的方案数,同样可以组合数计算。然后就做完了。

复杂度O(n)O(n)O(n)

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int mod=998244353;
const int N=2e6+5;
int T,n,p[N],vs[N];
ll fac[N],inv[N],bit[N],res;
void add(ll &x,ll y){x=(x+y)%mod; 
}
ll fpow(ll x,ll y=mod-2){ll z(1);for(;y;y>>=1){if(y&1)z=z*x%mod;x=x*x%mod;}return z;
}
void init(int n){fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;inv[n]=fpow(fac[n]);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod;
}
ll binom(ll x,ll y){return fac[x]*inv[y]%mod*inv[x-y]%mod;
} 
ll G(int a,int b,int c,int d){if(c>=a&&d>=b)return binom(c+d-a-b,c-a);return 0;
}
ll F(int a,int b,int c,int d){if(c>=a&&d>=b&&b>=a){return G(a,b,c,d)-G(b+1,a-1,c,d);}return 0;
}
int main(){    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);init(2e6);cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++)cin>>p[i],vs[i]=0;res=0;int tp=0,j=1;for(int i=0;i<n;i++){add(res,F(i,max(tp,p[i+1])+1,n,n));while(j<=n&&vs[j])j++;if(j<tp&&j>p[i+1]){add(res,F(i+1,tp,n,n));}if(p[i+1]<tp&&p[i+1]!=j){break;}tp=max(tp,p[i+1]);vs[p[i+1]]=1;}cout<<(res+mod)%mod<<"\n";}
}
http://www.lryc.cn/news/43958.html

相关文章:

  • 【Ruby学习笔记】3.Ruby 语法及数据类型
  • 华为OD机试题【字符匹配】用 Java 解 | 含解题说明
  • JavaScript数组对象的浅拷贝与深拷贝(二)实现对象深拷贝的方法(5种)
  • iPhone屏幕适配(之屏幕尺寸)
  • 手机变砖修复神器之 8 个的 Android手机系统修复工具
  • 稀疏矩阵(Sparse Matrix)
  • 深度学习中的损失函数
  • English Learning - L2 语音作业打卡 辅音咬舌音 [θ] [ð] Day29 2023.3.21 周二
  • 【原始者-综述】
  • C++内存模型
  • 八股+面经
  • MySQL更新数据流程
  • 测试开发进阶系列课程
  • Qt源码阅读(三) 对象树管理
  • 【Python入门第四十二天】Python丨NumPy 数组裁切
  • Anaconda配置Python新版本tensorflow库(CPU、GPU通用)的方法
  • 加载模型时出现 OSError: Unable to load weights from pytorch checkpoint file 报错的解决
  • sessionStorage , localStorage 和cookie的区别
  • C# 实例详解委托之Func、Action、delegate
  • 如何选电脑
  • SpringBoot项目创建
  • 神经衰弱该如何判断?确诊为神经衰弱,日常要做好这7大护理!
  • Linux之进程替换
  • 关于清除浮动
  • Uber H3 index 地图索引思考
  • 多线程的几种状态
  • 【算法题】1574. 删除最短的子数组使剩余数组有序
  • 理解对数——金融问题中的自然对数(以e为底的对数)
  • vue2进阶学习之路
  • 决策树ID3算法