首页 > 其他分享 >P8859 冒泡排序

P8859 冒泡排序

时间:2023-07-27 12:45:15浏览次数:46  
标签:P8859 return int 冒泡排序 vector operator modint mod

我回来了。

参考:https://www.luogu.com.cn/blog/_post/509374https://www.luogu.com.cn/blog/_post/510710

考虑 type 1,注意到 \(1\) 是不能被超越的,且一个数操作多次不优,因此第一步操作 \(1\) 不劣。因此从小到大归位每个数不劣,答案即为总数减去前缀 \(\max\) 的数目。从小到大插入并计数即可。

考虑对序列做所有轮换,最优解一定在这 \(n\) 种轮换断环成链后的答案中。于是对所有轮换找前缀 \(\max\) 之 \(\max\) 即可。

用后继刻画轮换。将每个点向后面离它最近的大于它的数值连有向边,则图中最长路即为答案。这会形成以 \(n\) 为根的内向树。

这样转化极好。它提供了设计子结构的方法。同时,它是双射:树与序列的数目都是 \((n-1)!\),一棵树一定能转化为一个序列,一个序列一定能转化成一棵树。

树转序列,递归:

  • 将 \(u\) 加入序列
  • 从小到大递归 \(u\) 的儿子

容易发现一定合法。

因此只需要对父亲编号大于儿子编号的树计数。

设 \(f_{i, j}\) 表示:\(i\) 点深度最大值为 \(j\) 的树的个数。转移时把一棵子树合并进当前树中:

\[f_{i+j, \max(d_1, d_2+1)} \gets \binom{i + j - 2}{i - 1} f_{i, d_1} f_{j, d_2} \]

在第二维度上记录前缀 \(\max\) 即可。

// start time : 
// debug time :
// end time : 
#include <bits/stdc++.h>
const int M = 505;

const int mod = 1e9 + 7;
struct modint {
  int x;
  modint(int o = 0) {x = o;}
  modint &operator = (int o) {return x = o, *this;}
  modint &operator += (modint o) {return x = x+o.x >= mod ? x+o.x-mod : x+o.x, *this;}
  modint &operator -= (modint o) {return x = x-o.x < 0 ? x-o.x+mod : x-o.x, *this;}
  modint &operator *= (modint o) {return x = 1ll*x*o.x%mod, *this;}
  modint &operator ^= (int b) {
    modint a = *this, c = 1;
    for (; b; b >>= 1, a *= a) if(b & 1) c *= a;
    return x=c.x, *this;
  }
  modint &operator /= (modint o) {return *this *= o ^= mod-2;}
  friend modint operator + (modint a, modint b) {return a += b;}
  friend modint operator - (modint a, modint b) {return a -= b;}
  friend modint operator * (modint a, modint b) {return a *= b;}
  friend modint operator / (modint a, modint b) {return a /= b;}
  friend modint operator ^(modint a,int b) {return a ^= b;}
  friend bool operator == (modint a, int b) {return a.x == b;}
  friend bool operator != (modint a, int b) {return a.x != b;}
  bool operator ! () {return !x;}
  modint operator - () {return x ? mod-x : 0;}
  bool operator < (const modint &b) const {return x < b.x;}
};
inline modint qpow(modint x, int y) {return x ^ y;}

std::vector<modint> fac, ifac, iv;

inline modint sign(int n) {return (n&1) ? (mod-1) : (1);}


modint solve1(int n, int m) {
  std::vector<std::vector<modint>> f(n + 1, std::vector<modint>(m + 1));
  f[0][0] = 1;
  for (int i = 1; i <= n; i++) {
    // f[i][0] = 1;
    for (int j = 1; j <= m; j++) {
      f[i][j] = f[i - 1][j - 1] + f[i - 1][j] * (i - 1);
    }
  }
  return f[n][m];
}

modint solve2(int n, int m) {
  std::vector<std::vector<modint>> f(n + 1, std::vector<modint>(n + 1));
  std::vector<std::vector<modint>> s(n + 1, std::vector<modint>(n + 1));
  std::vector<std::vector<modint>> C(n + 1, std::vector<modint>(n + 1));
  C[0][0] = 1;
  for (int i = 1; i <= n; i++) {
    C[i][0] = 1;
    for (int j = 1; j <= i; j++)
      C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
  }
  f[1][1] = 1;
  for (int i = 1; i <= n; i++)
    s[1][i] = 1;
  for (int t = 2; t <= n; t++) {
    // f[t][t] = 1;
    for (int i = 1; i < t; i++) {
      int j = t - i;
      modint c = C[i + j - 2][i - 1];
      for (int d = 1; d <= t; d++) {
        f[t][d] += c * f[i][d] * s[j][d - 1]; // d = d1 >= d2 + 1
        f[t][d] += c * s[i][d - 1] * f[j][d - 1]; // d = d2 + 1 > d1
      }
    }
    for (int i = 1; i <= n; i++)
      s[t][i] = s[t][i - 1] + f[t][i];
  }
  return f[n][m];
}

int main() {
  int n, m, t; scanf("%d %d %d", &n, &m, &t);
  if (t == 1) printf("%d\n", solve1(n, n - m));
  else printf("%d\n", solve2(n, n - m));
  return 0;
}
/*
stupid mistakes:
  - 初始化 f[1][1] = 1 而非 f[1][0]
  - 链的情况在 i=1, d=t 时考虑,不用特判
  - 前缀和取到 n
*/

标签:P8859,return,int,冒泡排序,vector,operator,modint,mod
From: https://www.cnblogs.com/purplevine/p/17584655.html

相关文章

  • 2023.7.19 周三:冒泡排序
    1importjava.sql.SQLOutput;2importjava.util.Arrays;3importjava.util.Scanner;4//冒泡排序5publicclasstest{6publicstaticvoidmain(String[]args){7int[]a={5,4,6,8,9,1,7,2,3};8intarray[]=sort(a);9S......
  • 一维数组之冒泡排序
    从b站上黑马程序员的C++课里学到的冒泡排序 1#include<iostream>2usingnamespacestd;3intmain()4{5intarr[6]={2,4,1,6,7,3};6for(inti=0;i<6;i++)//数组遍历7{8cout<<arr[i]<<"";9}1......
  • PHP实现冒泡排序
    冒泡排序的原理:1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。3.针对所有的元素重复以上的步骤,除了最后一个。4.持续每次对越来越少的元素重复上面的步骤,直到没有......
  • 冒泡排序
    #冒泡最大的在最后面#冒泡最大的在后面lis=[4,3,2,1]forjinrange(len(lis)-1):#外循环了len-1次flag=False#添加标记没有交换foriinrange(len(lis)-1):#内循环后找到本次最大的放到了最后iflis[i]>lis[i+1]:lis[i]......
  • 【基础算法】八大排序算法:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序(快排)
    ✔️前言......
  • 【前端教程03】for循环冒泡排序、去重、查找重复元素
    //升序constbubbleSort=(arr)=>{for(leti=0;i<arr.length;i++){for(letj=0;j<arr.length-i;j++){if(arr[j]>arr[j+1]){lettmp=arr[j];arr[j]=arr[j+1];arr[j+1]=tmp;......
  • 冒泡排序
    #include<stdio.h>voidbubble_sort(int*arr,intsz){ //确定冒泡函数的趟数 inti=0; for(i=0;i<sz-1;i++) { //每一趟冒泡排序 intj=0; intflag=0; for(j=0;j<sz-1-i;j++) { if(arr[j]>arr[j+1]) { inttmp......
  • 编程初学者入门7_公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分
    题目描述公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分制),去掉一个最高分和一个最低分,输出每组的平均成绩。输入描述:一行,输入7个整数(0~100),代表7个成绩,用空格分隔。输出描述:一行,输出去掉最高分和最低分的平均成绩,小数点后保留2位,每行输出后换行。示例1我的......
  • 26.冒泡排序
    每当皇帝选妃时,首席太监小桂子总是忍不住在旁边偷窥这些候选的美女,有一次他发现做为伴读小书童的你居然犯了个常人都可以轻易看出的错误,有几位候选的美女站成如下一排:当我们采用前面的选择排序时,我们仍然要将候选者遍历5遍,才能完成最终的排序,但其实,本身这些美女除了第一个外,已经......
  • Python 算法之冒泡排序
    Python算法之冒泡排序冒泡排序冒泡排序算法的原理如下:(从后往前)1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。3、针对所有的元素重复以上的步骤,除了最后一......