A little known fact about cows is that they have their own version of the alphabet, the "cowphabet". It consists of the 26 letters 'a' through 'z', but when a cow speaks the cowphabet, she lists these letters in a specific ordering that might be different from the order 'abcdefghijklmnopqrstuvwxyz' we are used to hearing.
To pass the time, Bessie's cousin Mildred has been humming the cowphabet over and over again, and Farmer Nhoj is curious how many times she's hummed it.
Given a lowercase string of letters that Farmer Nhoj has heard Mildred say, compute the minimum number of times Mildred must have hummed the entire cowphabet in order for Farmer Nhoj to have heard the given string. Farmer Nhoj isn't always paying attention to what Mildred hums, and so he might have missed some of the letters that Mildred has hummed. The string you are told consists of just the letters that he remembers hearing.
Note: the time limit per test case on this problem is twice the default.
The only line of input contains the string of lowercase letters that Farmer Nhoj heard Mildred say. This string has length at least?11?and at most?105105.
Print the minimum number of times Mildred must have hummed the entire cowphabet.
mildredree
3
Mildred must have hummed the cowphabet at least three times. It is possible for Mildred to have only hummed the cowphabet three times if the cowphabet starts with "mildre" and Farmer Nhoj heard the letters in uppercase as denoted below.
MILDREabcfghjknopqstuvwxyz milDREabcfghjknopqstuvwxyz mildrEabcfghjknopqstuvwxyz
Problem credits: Nick Wu and Brian Dean
[/hide]
(Analysis by Benjamin Qi, Sofia Yang)
Let?c1,c2,…,cNc1,c2,…,cN?be the distinct letters that appear in the input string (all other letters can be ignored). Note how the scoring gives bounds on?NN?(rather unoriginally). Specifically,?N≤8N≤8?for the first few test cases and?N≤20N≤20?for the remaining test cases.
For a permutation?pp?of?1…N1…N, define?evaluate([p1,p2,…,pN])evaluate([p1,p2,…,pN])?to be the minimum number of times the cowphabet is hummed when the order of the cowphabet is fixed as?[cp1,cp2,…,cpN][cp1,cp2,…,cpN]. From the analysis for the Bronze version of this problem,?evaluate(p)evaluate(p)?equals one plus the number of consecutive substrings of the form?cpicpjcpicpj?where?i≥ji≥j.
Defining?adjacent[i][j]adjacent[i][j]?to be the number of consecutive substrings of the form?cicjcicj?in the input string, we may rewrite?evaluate(p)evaluate(p)?as:
The answer is equal is to compute the minimum of?evaluate([p1,p2,…,pN])evaluate([p1,p2,…,pN])?over all permutations?pp?of?1…N1…N:
Subtask:?N≤8N≤8
Compute all entries of?adjacentadjacent?in?O(length(input string))O(length(input string))?time. Then iterate over all?N!N!?possible permutations?pp?of the cowphabet. For each?pp,?evaluate(p)evaluate(p)?may be computed in?O(N2)O(N2)?time.
Time Complexity:?O(N!?N2+length(input string))O(N!?N2+length(input string))
#include <bits/stdc++.h> using namespace std; int main() { string heard; cin >> heard; int n = 0; // number of unique letters map<char,int> index; for (char letter: heard) if (!index.count(letter)) index[letter] = n++; vector<vector<int>> adjacent(n, vector<int>(n)); for (int j = 1; j < heard.size(); ++j) ++adjacent[index[heard[j-1]]][index[heard[j]]]; vector<int> p(n); iota(begin(p), end(p), 0); // 0 ... n-1 int ans = INT_MAX; do { int cur_ans = 1; for (int i = 0; i < n; ++i) for (int j = 0; j <= i; ++j) cur_ans += adjacent[p[i]][p[j]]; // now cur_ans = evaluate(p) ans = min(ans, cur_ans); } while (next_permutation(begin(p), end(p))); cout << ans << "\n"; }
Full Solution:?N≤20N≤20
The idea is to apply dynamic programming on subsets of the cowphabet.
Let?S={i1,i2,…,in}S={i1,i2,…,in}?be the indices of any subset of the letters of the cowphabet (0≤n≤N0≤n≤N). We initially defined?evaluateevaluate?only when?pp?was a permutation of?1…N1…N, but observe that the definition naturally extends to the case where?pp?is a permutation of?SS. Then similarly to our definition of?ansans?above, we may define
To compute this quantity when?SS?is nonempty, suppose that we fix?pnpn, the index of the character in?SS?that appears last in the cowphabet. The minimum number of times the cowphabet needs to be sung considering only the remaining indices in?SS?is precisely?dp[S?{pn}]dp[S?{pn}], and then we need to add the number of consecutive pairs between?pnpn?and all the letters in?SS. Specifically, we may write
For example, for the input “abcac,”?adjacentadjacent?would be as follows:
+===+===+===+===+ | | a | b | c | +===+===+===+===+ | a | 0 | 1 | 1 | +---+---+---+---+ | b | 0 | 0 | 1 | +---+---+---+---+ | c | 1 | 0 | 0 | +---+---+---+---+
And the calculations would be as follows:
dp[000] = 1; dp[001] = 1; dp[010] = 1; dp[011] = 1; dp[001] + adjacent[b][b] + adjacent[b][c] = 1 dp[010] + adjacent[c][b] + adjacent[c][c] = 2 dp[100] = 1; dp[101] = 2; dp[001] + adjacent[a][a] + adjacent[a][c] = 2 dp[100] + adjacent[c][a] + adjacent[c][c] = 2 dp[110] = 1; dp[010] + adjacent[a][a] + adjacent[a][b] = 2 dp[100] + adjacent[b][a] + adjacent[b][b] = 1 dp[111] = 2; dp[011] + adjacent[a][a] + adjacent[a][b] + adjacent[a][c] = 3 dp[101] + adjacent[b][a] + adjacent[b][b] + adjacent[b][c] = 3 dp[110] + adjacent[c][a] + adjacent[c][b] + adjacent[c][c] = 2
In the code, we represent?SS?with a length?NN?bitmask?maskmask, where the?ii'th bit of?maskmask?is 1 if?i∈Si∈S, and 0 otherwise. The final answer corresponds to?dp[(1?N)?1]dp[(1?N)?1], corresponding to?S={1,2,…,N}S={1,2,…,N}.
Time Complexity:?O(2N?N2+length(input string))O(2N?N2+length(input string))
Danny Mittal's code:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class UdderedButNotHerdGold { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String heard = in.readLine(); // Index stores the index of every unique letter in the string. Map<Character, Integer> index = new HashMap<>(); for (char letter : heard.toCharArray()) { if (!index.containsKey(letter)) { index.put(letter, index.size()); } } // Number of unique letters int n = index.size(); /* * adjacent[i][j] is the number of pairs where * the ith unique letter appears directly before the jth. */ int[][] adjacent = new int[n][n]; for (int j = 1; j < heard.length(); j++) { adjacent[index.get(heard.charAt(j - 1))][index.get(heard.charAt(j))]++; } /* * DP on subsets. * (1 means this bit is in the subset, 0 means not) */ int[] dp = new int[1 << n]; dp[0] = 1; for (int mask = 1; mask < (1 << n); mask++) { dp[mask] = heard.length(); for (int j = 0; j < n; j++) { // If jth letter comes last in the cowphabet out of those in the subset if ((mask & (1 << j)) != 0) { // this is the answer for the state corresponding to removing j from mask int sum = dp[mask ^ (1 << j)]; // add the number of consecutive pairs between j and all bits in mask for (int k = 0; k < n; ++k) if ((mask & (1 << k)) != 0) sum += adjacent[j][k]; dp[mask] = Math.min(dp[mask], sum); } } } // the answer corresponds to all n bits set System.out.println(dp[(1 << n) - 1]); } }
It was possible (but not necessary) to remove a factor of?NN?from the runtime.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class UdderedButNotHerdGold { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String heard = in.readLine(); Map<Character, Integer> index = new HashMap<>(); for (char letter : heard.toCharArray()) { if (!index.containsKey(letter)) { index.put(letter, index.size()); } } int n = index.size(); int[][] adjacent = new int[n][n]; for (int j = 1; j < heard.length(); j++) { adjacent[index.get(heard.charAt(j - 1))][index.get(heard.charAt(j))]++; } int[][] sums = new int[n][1 << n]; int[] dp = new int[1 << n]; dp[0] = 1; for (int mask = 1; mask < (1 << n); mask++) { dp[mask] = heard.length(); int k = 0; while ((mask & (1 << k)) == 0) { k++; } for (int j = 0; j < n; j++) { sums[j][mask] = sums[j][mask - (1 << k)] + adjacent[j][k]; if ((mask & (1 << j)) != 0) { dp[mask] = Math.min(dp[mask], dp[mask - (1 << j)] + sums[j][mask]); } } } System.out.println(dp[(1 << n) - 1]); } }
However, this solution uses?Θ(N?2N)Θ(N?2N)?memory. We can reduce the required memory to?O(2N)O(2N)?and the runtime by a constant factor by using two 2D arrays to store the sums rather than one:
#include <bits/stdc++.h> #define f first #define s second using namespace std; int stor1[1<<10][20], stor2[1<<10][20]; int main() { string s; cin >> s; map<char,int> m; for(char c: s) m[c] = 0; int cnt = 0; for (auto& t: m) t.s = cnt++; int N = m.size(); assert(N <= 20); vector<vector<int>> oc(N,vector<int>(N)); for (int i = 0; i+1 < s.size(); ++i) ++oc[m[s[i]]][m[s[i+1]]]; vector<int> dp(1<<N,1e9); dp[0] = 1; int bits = N/2; for (int j = 0; j < N; ++j) { for (int i = 0; i < 1<<bits; ++i) for (int k = 0; k < bits; ++k) if (i&1<<k) stor1[i][j] += oc[k][j]; for (int i = 0; i < 1<<(N-bits); ++i) for (int k = 0; k < N-bits; ++k) if (i&1<<k) stor2[i][j] += oc[bits+k][j]; } for (int i = 0; i < 1<<N; ++i) for (int j = 0; j < N; ++j) if (i&1<<j) { int sum = dp[i^1<<j]; sum += stor1[i&((1<<bits)-1)][j]; sum += stor2[i>>bits][j]; dp[i] = min(dp[i],sum); } cout << dp[(1<<N)-1] << "\n"; }
[/hide]
? 2025. All Rights Reserved. 沪ICP备2023009024号-1