題目大意
將給你一個字串 s,以及 k,請你找出一個字串比 s 下一個小的字串並且裡面的同個字母數量都能 mod k == 0 還有產生的字串長度必須等於 s
題目連結
重點觀念
分析 對不起,我覺得我的重點觀念很像在講幹話…,但設計解題就是這樣嘛RRRR。 相信大家都能夠推出重點來,只是大家不知道要怎麼寫這題目,有抓到重點但是寫不出來的那種感覺。
以下是我進行整理的點,由�我在 大大中領會出來的。
,如果不成立就可以輸出 -1 因為如果不等於的話,勢必會有一個英文字母沒有辦法 mod k
再來我們判斷需不需要修改字串中的字元,如果不用就直接輸出原本的字串 這點很重要,如果我們有先處理這步驟,那後面的程式會好寫很多,我就是沒想到這步才卡住
需要修改時,那我們就要進行以下處理
從題目的字串尾巴開始判斷是否要修改字元 由於題目只能找比 s 下一個小的字串,因此我們先修改字串尾巴的字元,能夠更快找到比 s 下一個小的字串
如果在某 index 下修改字元,判斷要填塞哪個字母才能符合同個字母數量都能 mod k == 0 這時,我們要計算出在某 index 前面的字串們,還要再塞入一個字元幾次,例如 ‘a’ 個字元兩次 才能符合同個字母數量都能 mod k == 0
推敲出公式 (k- 現在某個字元在某 index 前面字串裡的數量 %k)%k
此公式為還要在幾個相同字元的數量才能符合同個字母數量都能 mod k == 0 假如一個字串 aabb
,k = 3,那我們勢必要在給各一個 a, b 才能符合同個字母數量都能 mod k == 0 此條件,可能會有人不太懂為甚麼前面要 (k -
and %k
,是為了假如現在某個字元在某 index 前面字串裡的數量 = 0 時,才不會出現需要 k 個字元的情況發生。
現在我們獲得這些重點後,我們就可以來寫程式了!一些重點與小技巧在程式碼那邊進行說明。
參考連結
心得 RRRRR,其實我應該寫得出這題的,只是我抓出了這些重點後還是沒有寫程式的想法,透過 �我在大大的程式碼後,我才發現有一個 sum
(題目程式碼的陣列,用於記錄在每個字串前綴長度時,每個字母的數量值) 是多麼重要的一件事情!我那時要是有想到他,我就會解出來了!
總之希望自己在學演算法是有意義的,我覺得我正在變聰明,我也從演算法中獲取了很多知識,似乎每天努力的學習就是寫演算法的義務吧!
嘛,我也不知道為甚麼我會走到這條路,總之我繼續加油吧!
題目程式碼 會在下面放一些簡單註解,供大家學習時參考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 #include <iostream> #include <bits/stdc++.h> #define LOCAL #define MAXN 100020 using namespace std ;int T, k, n;int cnt[30 ], sum[MAXN][30 ], now;string s; int check (int x) { for (int i = s[x]-'a' +1 ; i < 26 ; i++){ memset (cnt, 0 , sizeof (cnt)); int remain = n-x-1 ; for (int j = 0 ; j < 26 ; j++){ now = sum[x][j]; if (j == s[x]-'a' ) now--; else if (i == j) now++; remain -= (k-now%k)%k; cnt[j] += (k-now%k)%k; if (remain < 0 ) break ; } if (remain < 0 ) continue ; cnt[0 ] += remain; return i; } return 0 ; } string solve () { if (s.length() % k != 0 ) return "-1" ; for (int i = 0 ; i < 26 ; i++) sum[0 ][i] = 0 ; for (int i = 0 ; i < n; i++){ sum[i][s[i] - 'a' ] += 1 ; for (int j = 0 ; j < 26 ; j++) sum[i+1 ][j] = sum[i][j]; } int flag = 1 ; for (int i = 0 ; i < 26 ; i++){ if (sum[n-1 ][i] % k != 0 ){ flag = 0 ; break ; } } if (flag == 1 ) return s; string ans = "" ; for (int i = n-1 ; i >= 0 ; i--){ flag = check(i); if (flag){ ans = s.substr(0 , i) + (char ) (flag+'a' ); for (int i = 0 ; i < 26 ; i++) ans += string (cnt[i], i+'a' ); return ans; } } return ans; } int main () {#ifdef LOCAL freopen("in1.txt" , "r" , stdin ); #endif cin >> T; while (T--){ cin >> n >> k >> s; cout << solve() << '\n' ; } return 0 ; }
思考流程 透過紙筆與黑板而思考而成的片段,放在網路上供我紀念XD
錯誤的程式碼就不放上來讓大家見笑了QQQQ。