牛客練習賽1 補題記錄
阿新 • • 發佈:2018-02-08
樹形 中文 push .html 分答 subst clas n) str
A 矩陣
中文題意,要找一個最大的k階子矩陣在原矩陣中出現過兩次。
需要將這個矩陣進行Hash,也就是需要二維Hash,先把每一行Hash了,再把每一列Hash了,有一點前綴的感覺。
預處理完Hash值之後,二分答案k,check過程是在$O(n ^ 2)$枚舉起點,這裏其實枚舉終點方便一些,邊界比較好處理,把每個k階矩陣的hash值存下來,最後看有沒有兩個一樣的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 567; 5 6 typedef unsigned long longView Codeull; 7 int n, m; 8 char mat[N][N]; 9 ull hs[N * N], hs1[N][N], hs2[N][N]; 10 ull pw1[N], pw2[N]; 11 ull seed1 = 17, seed2 = 9191891; 12 13 bool check(int k) { 14 int tot = 0; 15 for (int i = k; i <= n; ++i) { 16 for (int j = k; j <= m; ++j) { 17 ull temp = hs2[i][j] - hs2[i][j - k] * pw1[k];18 temp -= hs2[i - k][j] * pw2[k]; 19 temp += hs2[i - k][j - k] * pw1[k] * pw2[k]; 20 hs[++tot] = temp; 21 } 22 } 23 24 sort(hs + 1, hs + 1 + tot); 25 for (int i = 1; i <= tot; ++i) { 26 if (hs[i] == hs[i - 1]) return 1; 27 } 28 return false; 29 } 30 31 intmain() { 32 pw1[0] = pw2[0] = 1; 33 for (int i = 1; i < N; ++i) { 34 pw1[i] = pw1[i - 1] * seed1; 35 pw2[i] = pw2[i - 1] * seed2; 36 } 37 38 scanf("%d%d", &n, &m); 39 for (int i = 1; i <= n; ++i) scanf("%s", mat[i] + 1); 40 41 for (int i = 1; i <= n; ++i) { 42 for (int j = 1; j <= m; ++j) { 43 hs1[i][j] = hs1[i][j - 1] * seed1 + (mat[i][j] - ‘a‘); 44 } 45 } 46 for (int i = 1; i <= n; ++i) { 47 for (int j = 1; j <= m; ++j) { 48 hs2[i][j] = hs2[i - 1][j] * seed2 + hs1[i][j]; 49 } 50 } 51 52 int mid, ans = 0, lb = 1, ub = min(n, m); 53 while (lb <= ub) { 54 mid = (lb + ub) / 2; 55 if (check(mid)) { 56 ans = mid; lb = mid + 1; 57 } else { 58 ub = mid - 1; 59 } 60 } 61 printf("%d\n", ans); 62 return 0; 63 }
B 樹
每條鏈上的顏色要一樣,題目其實和樹形無關。
狀態表示:dp(i, j)表示前i個結點染了j個顏色的方案數,那麽新加一個點進去,要麽和前面的結點是同一個顏色,要麽就是新的顏色。
轉移方程:dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * (k - j + 1));
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 345; 5 const int mod = 1e9 + 7; 6 int n, k; 7 vector<vector<int>> T; 8 long long dp[N][N]; 9 int main() { 10 scanf("%d%d", &n, &k); 11 T.resize(n); 12 for (int i = 1; i < n; ++i) { 13 int x, y; 14 scanf("%d%d", &x, &y); 15 } 16 dp[0][0] = 1; 17 for (int i = 1; i <= n; ++i) { 18 for (int j = 1; j <= k; ++j) { 19 dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * (k - j + 1)) % mod; 20 } 21 } 22 long long ans = 0; 23 for (int i = 1; i <= k; ++i) (ans += dp[n][i]) %= mod; 24 printf("%lld\n", ans); 25 return 0; 26 }View Code
C 圈圈
思路 Fighting Heart
循環移位的同時序列每個數都模m的++,要求循環移位後,字典序最小的那個序列的第k項。
這種循環移位的,一般可以先把序列復制一遍,變成2n的長度,比較方便。
可以發現,每個元素如果有那麽僅有一次變為0的機會,當有數字變為0了,需要重新判斷。
枚舉每一輪會變為0的位置,字典序最小肯定是從這些位置中產生的。
然後又是Hash,二分找兩個串的lcp,判斷後一位的大小來比較兩個串。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef unsigned long long ull; 5 const int N = 50000 * 2 + 5; 6 int n, m, k; 7 int a[N]; 8 int ans[N]; 9 vector<int> pos[N]; 10 ull sd, hs[N], sdp[N]; 11 12 bool check(int x, int y, int L) { 13 if (L == 0) return 1; 14 ull u = hs[x] - hs[x + L] * sdp[L]; 15 ull v = hs[y] - hs[y + L] * sdp[L]; 16 return u == v; 17 } 18 // ok(x, y, l) : substr(x, l) > substr(y, l) ? 19 bool ok(int x, int y, int t) { 20 int lb = 0, ub = n, ret = -1; 21 while (lb <= ub) { 22 int mid = (lb + ub) / 2; 23 if (check(x, y, mid)) { 24 ret = mid; lb = mid + 1; 25 } else { 26 ub = mid - 1; 27 } 28 } 29 if (ret == n) return 0; 30 return ((a[x + ret] + t) % m) < ((a[y + ret] + t) % m); 31 } 32 33 int main() { 34 scanf("%d%d%d", &n, &m, &k); 35 36 for (int i = 0; i < n; ++i) { 37 scanf("%d", a + i); 38 a[n + i] = a[i]; 39 pos[(m - a[i]) % m].push_back(i); 40 } 41 42 sd = 19260817; sdp[0] = 1; 43 for (int i = 1; i < N; ++i) { 44 sdp[i] = sdp[i - 1] * sd; 45 } 46 hs[2 * n] = 0; 47 for (int i = 2 * n - 1; ~i; --i) { 48 hs[i] = hs[i + 1] * sd + a[i]; 49 } 50 51 int x = 0; 52 for (int i = 0; i < n; ++i) { 53 if (ok(i, x, 0)) x = i; 54 } 55 ans[0] = a[x + k - 1]; 56 for (int i = 1; i < m; ++i) { 57 if (pos[i].empty()) { 58 ans[i] = ans[i - 1] + 1; 59 continue; 60 } 61 x = pos[i][0]; 62 for (int j = 1; j < (int)pos[i].size(); ++j) { 63 if (ok(pos[i][j], x, i)) x = pos[i][j]; 64 } 65 ans[i] = (a[x + k - 1] + i) % m; 66 } 67 68 for (int i = 0; i < m; ++i) { 69 printf("%d\n", ans[i]); 70 } 71 }View Code
牛客練習賽1 補題記錄