#include <iostream> using namespace std; /* n - długość tekstu 1 <= n < 200000 Teksty krótsze niż 3 znaki, to nie ma ryzyka, trudnych fragmentów jest "0". Dla dłuższych tekstów możemy oznaczyć sobie każsą trójkę jako ryzykowną (cyfra - wartośc tylko dla przejrzystości dalszej analizy) lub nie (-), i tak dla przykładowego teksu mam: tekst: takakostkajakszescian spółgłoski/samogłoski: '.'.'.'''.'.'''.''..' ryzykowne trójki: ------1-----2------ Teraz chcąc ocenić ryzykowne czkórki, badam kolejne dwie ryzykowne trójki i jeśli choć jedna z nich była ryzykowna, to czwórka też jest ryzykowna. Tak samo dla piątek i kolejnych ciągów. Przykład: 111111111 ryzykowne pozycja: 0123456789012345678 ciągi: 3-ki: ------1-----2------ 2 4: -----11----22----- 4 5: ----111---222---- 6 . ---1111--2222--- 8 . --11111-22222-- 10 . -111111222222- 12 1111112222222 13 111112222222 12 11112222222 11 1112222222 10 112222222 9 12222222 8 2222222 7 ... 2 Widać, że każda ryzykowna trójka tworzy równoległobok ryzykownych n-tek, o wymiarach: (odległość odległość od początku + 1) x (odległość do następnej ryzykownej) Dla ostatniej zamiast odległości do następnej liczymy odległość do końca. m - liczba wszystkich trójek (m = n - 2) s - liczba ryzykownych trójek t - ciąg ryzykownych trójek (prawda lub fałsz - zamiast cyfr), pierwszy element ciągu, to t(0) na końcu ciągu t dodajemy strażnika t(s) = m Liczba wszystkich ryzykownych podciągów to: sum = SUMA [po i=0..s-1] (t(i) + 1) * (t(i+1) - t(i)) Dla powyższego przykładu mamy: s = 2 t = 6, 12, 19 sum = (6 + 1) * (12 - 6) + (12 + 1) * (19 - 12) = 133 max_sum ~= max_n ^ 2 / 2 = (2*10^5)^2 /2 = 2 * 10^10 => long long */ bool isVowel(char letter) { if (letter == 'a' || letter == 'e' || letter == 'i' || letter == 'o' || letter == 'u' || letter == 'y') { return true; } return false; } int main() { string text; getline(cin, text); long long n = text.size(); if (n < 3) { cout << 0 << endl; return 0; } long long m = n - 2; string::iterator textIt = text.begin(); char c; bool prev2Vowel = isVowel(*textIt); ++textIt; bool prev1Vowel = isVowel(*textIt); ++textIt; bool currVowel; long long sum = 0; long long lastRiskyTrioIndex = -1; long long currTrioIndex = -1; for (; textIt != text.end(); ++textIt) { ++currTrioIndex; currVowel = isVowel(*textIt); if ((prev2Vowel && prev1Vowel && currVowel) || !(prev2Vowel || prev1Vowel || currVowel)) { if (lastRiskyTrioIndex >= 0) { sum += (lastRiskyTrioIndex + 1) * (currTrioIndex - lastRiskyTrioIndex); } lastRiskyTrioIndex = currTrioIndex; } prev2Vowel = prev1Vowel; prev1Vowel = currVowel; } if (lastRiskyTrioIndex >= 0) { sum += (lastRiskyTrioIndex + 1) * (m - lastRiskyTrioIndex); } cout << sum << endl; return 0; }
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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | #include <iostream> using namespace std; /* n - długość tekstu 1 <= n < 200000 Teksty krótsze niż 3 znaki, to nie ma ryzyka, trudnych fragmentów jest "0". Dla dłuższych tekstów możemy oznaczyć sobie każsą trójkę jako ryzykowną (cyfra - wartośc tylko dla przejrzystości dalszej analizy) lub nie (-), i tak dla przykładowego teksu mam: tekst: takakostkajakszescian spółgłoski/samogłoski: '.'.'.'''.'.'''.''..' ryzykowne trójki: ------1-----2------ Teraz chcąc ocenić ryzykowne czkórki, badam kolejne dwie ryzykowne trójki i jeśli choć jedna z nich była ryzykowna, to czwórka też jest ryzykowna. Tak samo dla piątek i kolejnych ciągów. Przykład: 111111111 ryzykowne pozycja: 0123456789012345678 ciągi: 3-ki: ------1-----2------ 2 4: -----11----22----- 4 5: ----111---222---- 6 . ---1111--2222--- 8 . --11111-22222-- 10 . -111111222222- 12 1111112222222 13 111112222222 12 11112222222 11 1112222222 10 112222222 9 12222222 8 2222222 7 ... 2 Widać, że każda ryzykowna trójka tworzy równoległobok ryzykownych n-tek, o wymiarach: (odległość odległość od początku + 1) x (odległość do następnej ryzykownej) Dla ostatniej zamiast odległości do następnej liczymy odległość do końca. m - liczba wszystkich trójek (m = n - 2) s - liczba ryzykownych trójek t - ciąg ryzykownych trójek (prawda lub fałsz - zamiast cyfr), pierwszy element ciągu, to t(0) na końcu ciągu t dodajemy strażnika t(s) = m Liczba wszystkich ryzykownych podciągów to: sum = SUMA [po i=0..s-1] (t(i) + 1) * (t(i+1) - t(i)) Dla powyższego przykładu mamy: s = 2 t = 6, 12, 19 sum = (6 + 1) * (12 - 6) + (12 + 1) * (19 - 12) = 133 max_sum ~= max_n ^ 2 / 2 = (2*10^5)^2 /2 = 2 * 10^10 => long long */ bool isVowel(char letter) { if (letter == 'a' || letter == 'e' || letter == 'i' || letter == 'o' || letter == 'u' || letter == 'y') { return true; } return false; } int main() { string text; getline(cin, text); long long n = text.size(); if (n < 3) { cout << 0 << endl; return 0; } long long m = n - 2; string::iterator textIt = text.begin(); char c; bool prev2Vowel = isVowel(*textIt); ++textIt; bool prev1Vowel = isVowel(*textIt); ++textIt; bool currVowel; long long sum = 0; long long lastRiskyTrioIndex = -1; long long currTrioIndex = -1; for (; textIt != text.end(); ++textIt) { ++currTrioIndex; currVowel = isVowel(*textIt); if ((prev2Vowel && prev1Vowel && currVowel) || !(prev2Vowel || prev1Vowel || currVowel)) { if (lastRiskyTrioIndex >= 0) { sum += (lastRiskyTrioIndex + 1) * (currTrioIndex - lastRiskyTrioIndex); } lastRiskyTrioIndex = currTrioIndex; } prev2Vowel = prev1Vowel; prev1Vowel = currVowel; } if (lastRiskyTrioIndex >= 0) { sum += (lastRiskyTrioIndex + 1) * (m - lastRiskyTrioIndex); } cout << sum << endl; return 0; } |