1. 程式人生 > >Aiiage Camp Day3 C Communist

Aiiage Camp Day3 C Communist

復雜度 gpo 等於 mes for ++ etc 最小 char

題意

  給兩行詞串。第二行無重復,第一行有重復。每次可以在第一行刪去一個和第二行的公共子序列。問最少幾次可以刪完。

  長度<1e5 26小寫字母

題解

  每次求最長公共子序列顯然會T。

  等價問題是,對第二行詞從小到大標號,第一行上升子序列個數。

  那麽只需要倒序掃第一行詞串。初始序列數為0,記錄每個序列當前最小值,初始為∞。若當前掃到的值大於等於每個序列當前最小值,則需要一個新的序列。否則更新第一個最小值比其大的序列的最小值。這個操作可以二分完成,總復雜度O(nlogn)。

 1 #include <bits/stdc++.h>
 2 using namespace
std; 3 4 vector<string> a, d; 5 map<string, int > h; 6 int f[100010]; 7 8 int main() 9 { 10 int T; 11 scanf("%d", &T); 12 getchar(); 13 while (T--) 14 { 15 a.clear(); 16 d.clear(); 17 h.clear(); 18 string s1, s2, s; 19 getline(cin, s1);
20 getline(cin, s2); 21 stringstream ss(s1); 22 while (ss >> s) 23 a.push_back(s); 24 stringstream sss(s2); 25 while (sss >> s) 26 d.push_back(s); 27 28 for (int i = 0; i < d.size(); ++i) 29 h[d[i]] = i;
30 31 for (int i = 0; i <= a.size(); ++i) 32 f[i] = 100010; 33 for (int i = a.size() - 1; i >= 0; --i) 34 { 35 int x = h[a[i]]; 36 int l(0), r(a.size()); 37 while (l < r) 38 { 39 int mid = (l + r) / 2; 40 if (f[mid] > x && mid == 0) 41 { 42 f[mid] = x; 43 break; 44 } 45 if (f[mid] <= x && f[mid + 1] > x) 46 { 47 f[mid + 1] = x; 48 break; 49 } 50 if (f[mid] <= x) 51 l = mid + 1; 52 else 53 r = mid; 54 } 55 } 56 for (int i = 0; i <= a.size(); ++i) 57 if (f[i] == 100010) 58 { 59 printf("%d\n", i); 60 break; 61 } 62 } 63 64 return 0; 65 }

Aiiage Camp Day3 C Communist