初賽筆記

XuOuXiao1024發表於2024-07-27

數學

排列組合

錯排問題:\(D_n=(n-1)(D_{n-1}+D_{n-2})\) \((D_1=0,D_2=1)\)

資料結構

出棧序列數量 卡特蘭數\(\displaystyle C_i=\frac{C^n_{2n}}{n+1}=\sum_{i=0}^{n} {C_i}{C_{n-i}}\)

一個結點的度為這個節點的子節點數,一棵樹的度為所有節點的度數最大值

二叉樹

  • 二叉樹中,編號為i的結點,父結點為\(\lfloor \frac{i}{2} \rfloor\),子結點分別為\(2i\)\(2i+1\)
  • \(i\)層最多有\(2^{i-1}\)個結點,深度為\(k\)的樹最多有\(2^k-1\)個結點
  • \(N=N_0+N_1+N_2\)\(N_2+1=N_0\)

有關定義

  • 不存在重邊與自環的圖,叫做簡單圖
  • 無向圖中任意兩個結點間都存在邊相連,叫做無向完全圖
  • 有向圖中任意兩個結點間都存在互為相反的兩條邊相連,叫做有向完全圖
  • 結點的度:圖中與結點相連的邊的數目
  • 入度:在有向圖中,以這個結點為終點的有向邊的數目
  • 出度:在有向圖中,以這個結點為起點的有向邊的數目
  • 在無向圖中,如果兩點間存在路徑(不一定直接到達),則稱兩點連通
  • 在有向圖中,如果兩點間可以互相到達,則稱兩點強聯通
  • 一個無向圖,若每兩個點都連通,則稱此圖為連通圖
  • 一個有向圖,若每兩個點都連通,則稱此圖為強連通圖

性質

  • \(圖中所有結點的度的總和=邊數 \times 2\)
  • 有向完全圖,共有\(n(n-1)\)條邊
  • 無向完全圖,共有\(\frac{n(n-1)}{2}\)條邊
  • \(n\)個點的連通圖,邊的數量至少為\(n-1\)
  • \(n\)個點的強連通圖,邊的數量至少為\(n\)

演算法

排序

不穩定的排序:選擇、希爾、快排、堆排

  • \(O(n^2)\):冒泡、選擇、插入、快排最壞
  • \(O(n\log{n})\):歸併、快排、堆排、希爾、sort
  • \(O(n)\):桶排、計數、基數

動態規劃

最大子段和

⚠️子段必須連續⚠️

\(dp_i\)代表以\(a_i\)為結尾的最大子段和

狀態轉移方程:\(dp_i=max({dp_{i-1}+a_i},{a_i})\)

最長上升子序列

⚠️子序列可以斷開⚠️

\(dp_i\)代表以\(a_i\)為結尾的最長上升子序列的長度

主要程式碼:

int ans=0;
for(int i=1;i<=n;i++){
    dp[i]=1;
    for(int j=1;j<i;j++){
        if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1);
    }
    ans=max(ans,dp[i]);
}

最長公共子序列

\(dp_{i,j}\)代表以\(s1_{i}\)\(s1\)的末尾,\(s2_j\)\(s2\)的末尾時的最長公共子序列長度

\[狀態轉移方程:dp_{i,j} = \begin{cases} dp_{i-1,j-1}+1 &\text{if } s1_i=s2_j \\ max(dp_{i-1,j},dp_{i-1,j}) &\text{if } s1_i \ne s2_j \end{cases} \]

01揹包

\(f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i])\)

for(int i=1;i<=n;i++){
   for(int j=m;j>=v[i];j--){
      dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
   }
}

完全揹包

\(f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i])\)

for(int i=1;i<=n;i++){
   for(int j=v[i];j<=m;j++){
      dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
   }
}

多重揹包

int cnt = 0;
for (int i = 1; i <= n; i ++ ){
   int a, b, s;
   int k = 1;
   cin >> a >> b >> s;
   while (k <= s){
      cnt ++ ;
      v[cnt] = a * k;
      w[cnt] = b * k;
      s -= k;
      k *= 2;
   }
   if (s > 0){
      cnt ++ ;
      v[cnt] = a * s;
      w[cnt] = b * s;
   }
}//二進位制最佳化操作
n = cnt;
for (int i = 1; i <= n; i ++ )
   for (int j = m; j >= v[i]; j -- )
      f[j] = max(f[j], f[j - v[i]] + w[i]);

相關文章