FZU Monthly-201901 tutorial


FZU Monthly-201901 tutorial

題目(難度遞增) easy easy-medium medium medium-hard hard
思維難度 AHG F B CE D
編碼難度 AH CEFG B D

A. RonTanYoYiSen

對於本題,你只需要FOR一遍判斷是不是回文串即可。不管一個字符串是不是回文串,只有將它反過來再寫一邊就可以構造出一個回文串。根據題意,如果是回文串則輸出“YES NO”,否則輸出“NO YES”。

復雜度\(O(N)\)

B. max position set

Tutorial 1. Bruce force

由於是字典序的緣故,所以我們從第一列開始看到最后一列,如果當前列選擇后,不會違背字典序,那么根據貪心思想這一列要,否則顯然不能取。這樣做 \(N\) 次,每次把新的一列加到前面選出來的字符串后面,check一下是否合法。總復雜度 \(O(N^3)\)

例子:

adc
bcd
加進第一列
a
b
合法,保留。加入第二列
ad
bc
不合法,撤銷。加入第三列
ac
bd
合法,保留。

Tutorial 2. Observe

觀察可以發現,每加入一列后,如果第 \(i\) 行的字典序小於第 \(i+1\) 行,那么之后怎么怎么加都不會再對着這兩行有影響,即:整個過程中需要考慮的一定是相鄰的且所有字符均一樣的字符串。所以標記一下 \(N-1\) 個相鄰關系中國哪些已經出現偏序,那些還沒有,不需要考慮前面的取的字符,只需要比較當前新加進的這一列即可(因為前面一定是一樣的)

這樣還是做 \(N\) 次,每次比較只花 \(O(N)\) 的時間,總復雜度 \(O(N^2)\)

C.Palindrome

畫圖把相同的字符連線會發現就只有4種情況,然后分類討論一下

  • m1:當m1時,任意長度為1的子串顯然都是回文串,所以答案是 \(k^n\)

  • m > n:與m==1情況是一樣的

  • m==n:這個時候只需要考慮前半部分,這時候答案分別是 \(k^{n/2}\)(n為偶數),\(k^{n/2+1}\)(n為奇數)

  • m < n: 當m為奇數,答案為\(k^2\),當m為偶數,答案為\(k\)

注:m > n 的時候,顯然怎么構造都滿足題意

復雜度為\(O(N)\)

D. special square

同樣的題目背景,經典題型是求面積最大的全1矩陣。先學習一下這道題的做法,關於這道題,演算法筆記上有非常詳盡的分析:http://www.csie.ntnu.edu.tw/~u91029/MaximumSubarray.html#2

這題的做法基本與那道經典題類似,一樣的按行or列枚舉,通過單調棧去check,核心就是滿足條件的矩形四條邊都要頂到障礙物,代碼基本與原經典題類似,理解原經典題后如還有細節有疑惑可見代碼。

復雜度為\(O(N^2)\)

//
//  solution.cpp
//  special-matrix
//
//  Created by 鄭浩暉 on 2018/12/19.
//  Copyright © 2018 鄭浩暉. All rights reserved.
//

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define sz(x) ((int)(x).size())
#define dd(x) cout << #x << " = " << (x) << ", "
#define de(x) cout << #x << " = " << (x) << endl
typedef pair<int, int> pii;

const int N = 5e3 + 7;
char s[N][N];
int n, m, up[N][N];
void solve()
{
    cin >> n >> m; m++;
    for (int i = 0; i < n; i++) { scanf("%s", s[i]);  s[i][m-1] = '0'; }
    for (int i = 0; i < m; i++) s[n][i]='0';
    for (int j = 0; j < m; j++) up[0][j] = s[0][j] == '1';
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < m; j++) {
            up[i][j] = s[i][j] == '1' ? up[i - 1][j] + 1 : 0;
        }
    }
    int ans = 0;
    for (int i = 0; i < n; i++) {
        stack<pii> stk;
        int max_col = -1;
        for (int j = 0; j < m; j++) {
            int pos = j;
            while (!stk.empty() && stk.top().second > up[i][j]) {
                if (stk.top().first <= max_col)
                    ans++;
                pos = stk.top().first;
                stk.pop();
            }
            if (s[i + 1][j] == '0') max_col = j;
            if (!stk.empty() && stk.top().second == up[i][j]) continue;
            if (up[i][j]) stk.push({pos, up[i][j]});
        }
    }
    cout << ans << endl;
}

int main()
{
    solve();
    return 0;
}

E.LiHuaAndPoker

分類討論

  • K = 1。這個情況,字符串的相對位置不變,所以可能最多只有n種(每一個字母做開頭),對n種情況做一個比較即可,復雜度可以是O(n),O(nlogn),O(n^2),O(n^2logn)均可以通過。
  • K > 1。對於K大於1的所有情況,任何字符串都能調整成他的最小字典序(想想為什么),即對原字符串從小到大排序。對於K>2的排序情況類似冒泡排序。

F.LiHuaAndArray

一個經典的標記技巧(延遲計算)。對所有的[L,R]區間,在L位置標記+1,在R位置標記-1。標記結束后統計每一對奇偶位置的前綴和,前綴和是奇數的就交換位置,是偶數的不做操作。

復雜度O(N)。

G.Assassin

模擬題,分階段模擬

  • 負一從A點出發追小號
  • 負一追到小號后回A點

注:有個學弟 “小號已經走的路程” 用了int變量,太心疼了

H.DeadlyShoot

這個題目在大一的c語言日常題目中出現過。

Tutorial 1. Bruce force

對着題意模擬一直做數位求和直到一位,然后分類找出最大的一組輸出。

Tutorial 2. Math

我們設一個數A的數位和為S,那么易得A和S同余於9。由此,反復求數位和直到只剩一位這個操作等價於對9取模。因此,按照所有數對9的余數進行分類,最后輸出余數最大的那一組即可,需要特別注意的是,當某個數能被9整除的時候,他最后得到的數位和是9而不是0。

復雜度為\(O(N)\)

**
**


博主只是友情提供代發服務


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM