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