
ä»æ¥ã¯ãåæã®æ°ãèšç®ããããã®ã¢ã«ãŽãªãºã ã«ã€ããŠèª¬æããŸããããã¯ãäœã®ããã«ãã©ãã§äœ¿çšãããããã©ã®ããã«è¿ éã«è¡ãããã©ããªèœãšãç©ŽãåŸ ã¡åããŠããããªã©ã§ãã ãã®åé¡ã解決ããããŸããŸãªæ¹æ³ãæ€èšããåæ¹æ³ã®é·æãšçæãèŠã€ããŠãã ããã ãã®èšäºã¯ã¬ãã¥ãŒã«ãªããŸããããã§äœã説æããªãå Žåã¯ãåžžã«ãã¹ãŠã®ãªã³ã¯ãæäŸãããã¹ãŠã詳现ã«èª¬æãããŠæãããããã«ããŸãã ãã®è³æããã¢ã«ãŽãªãºã åéã®åå¿è ãšçµéšè±å¯ãªããã°ã©ãã®äž¡æ¹ã«ãšã£ãŠèå³æ·±ããã®ã«ãªãããšãé¡ã£ãŠããŸãã ãŸããããèå³ãããã°ãã«ããããé¡ãããŸãïŒ
ãããããåæãšã¯äœããèŠããŠãã䟡å€ããããŸãã
Palindrome-æ°åïŒ404ãªã©ïŒãæåã®çµã¿åãããäž¡æ¹åã§çããèªã¿ãããåèªãŸãã¯ããã¹ãã äžå€®ã«é¢ããŠå¯Ÿç§°ãªæåã»ããã¯ãåæãšåŒã°ããããšããããŸãïŒ ãŠã£ãããã£ã¢ããã®æç²ïŒ
å®çŸ©ã¯éåžžã«ç°¡åã§æ確ã§ãã ãã®æçš¿ã§ã¯ãåæåèªïŒããããã¯ãã¯ãªã©ïŒãæ€èšããŸãã ããããããã¯ã¢ã«ãŽãªãºã ãä»ã®ç¶æ³ã«é©çšã§ããªãããšãæå³ãããã®ã§ã¯ãããŸããã å°ãç¯å²ãçããŠãã ããã
ããªã³ãããŒã ãæ¢ãå¿ èŠãããã®ã¯ãªãã§ããïŒ
å®éãæ¥åžžç掻ã§åæãæ¢ãå¿ èŠã¯ã»ãšãã©ãããŸããã ããã¯éåžžã«å ·äœçãªã¿ã¹ã¯ã§ãã æååã¢ã«ãŽãªãºã ã«ã€ããŠè©±ããšãããªã³ãããŒã ã®æ°ãèŠã€ããããããæååã§åãéšåæååæ€çŽ¢ãèŠã€ããå¯èœæ§ãé«ããªããŸãã ãããã£ãŠãæç®ã®å ±éã¯ã¯ããã«åŒ±ãã§ãã
äž»ãªçšéã®1ã€ã¯ãã¹ããŒã/ãªãªã³ããã¯ããã°ã©ãã³ã°ã§ãã ããã«ã¯ååãªã¿ã¹ã¯ããããŸãã ã¿ã¹ã¯ã¯æžãããŠãããåå è ã¯ãã§ã«ããã解決ããæ¹æ³ãèããŠããŸãã å人çãªçµéšããèšããšããã®ãããªã¿ã¹ã¯ã«åºäŒã£ãã®ã¯2ã3åã ãã§ãããããããã¯ãã¹ãŠãããªãã®ã¿ã¹ã¯ã¯ããã«ãããèããªãã§ãã¢ã«ãŽãªãºã ãæžãã ãããšããã«ããŽãªã®ãã®ã§ããã ã€ãŸããã¹ã¿ããã£ã³ã°ã¢ã«ãŽãªãºã ã®åçŽãªæ©æ¢°çã¡ã¢ãªãéçºããèå³æ·±ãã¿ã¹ã¯ã§ã¯ãããŸããã
ããªã³ãããŒã ãèŠã€ããããå®çšçãªã¢ããªã±ãŒã·ã§ã³ã¯ãçç©åŠçã¢ã«ãŽãªãºã ã§ãã åãWikipediaãšWikiã®äžã®ãªã³ã¯ã«ãããšãçç©åŠçååç©ã®åæã¯ãããŸããŸãªçç©åŠçååç©ã®ç¹æ§ã«éèŠãªåœ¹å²ãæãããŠããŸãã ç§ã¯çç©åŠãèŠæãªã®ã§ãããèå³ãããã°ããã詳现ãªæ å ±ãèªåã§èŠã€ããããšãã§ããŸãã
ãŸããç§ãã¡ã¯å®å šã«åœ¹ã«ç«ããªãããšãããã€ããã¯ãªãããšãããããŸããã ã¢ã«ãŽãªãºã ã«ç§»ããŸãããïŒ
泚ïŒä»¥äžã®ãã¹ãŠã®ã¢ã«ãŽãªãºã ã§ã¯ãåäžã®æåã¯åæãšã¯èŠãªãããŸããã ãåãã®ããã«ãåäžã®æåãèæ ®ããå¿ èŠãããå Žåãããã¯ç°¡åã«ä¿®æ£ã§ããŸãã
0ïŒOïŒN ^ 3ïŒã®æŒžè¿çæ¯ãèããæã€æãå¹³å¡ãªã¢ã«ãŽãªãºã
bool SlowN3::isPalindrom(int leftBorder, int rightBorder) { while(leftBorder <= rightBorder) { if(str[leftBorder] != str[rightBorder]) { return false; } ++leftBorder; --rightBorder; } return true; } long long SlowN3::operator ()() { for(int leftBorder = 0;leftBorder < str.length(); ++leftBorder) { for(int rightBorder = leftBorder + 1; rightBorder < str.length(); ++rightBorder) { if( isPalindrom(leftBorder, rightBorder) ) { ++cntPalindromes; } } } return cntPalindromes; }
ãã¹ãŠã®ãœãŒã¹ã¯C ++ã§ããããããã¯ç§ãã¡ã«ãšã£ãŠèå³æ·±ãã¯ã©ã¹ã®éèŠãªéšåã«ãªãããšãããã«èŠåããããšæããŸãã
ã¢ã«ãŽãªãºã ã¯æããé¡ãã§ããæååããããç¹å®ã®æååã®éšåæååã®å é ãžã®ãã€ã³ã¿ããããç¹å®ã®éšåæååã®æ«å°Ÿãžã®ãã€ã³ã¿ããããŸãã 2ã€ã®ãã¹ããããã«ãŒãã§ãéšåæååã®å¢çãå埩åŠçããéšåæååãåæã§ãããã©ãããç°¡åã«ç¢ºèªããŸãã è€éãªããšã¯äœããããŸããã
ããããããã¯ãã¹ãŠéåžžã«ãã£ãããšåäœããŸãã ãªãã§ïŒ ã¯ããNåïŒNã¯åžžã«æååã®é·ãã«ãªãïŒãã2ä¹ãããããç¹ãéšåæååã®å¢çããœãŒãããææªã®å Žåã¯OïŒNïŒã«ã€ããŠããåæã®åéšåæååããã§ãã¯ããŸãã
ãã®æ¹æ³ã®å©ç¹ã¯ã»ãšãã©ãããŸããã
+å®è£ ãç°¡åã å®éãããã«ãã°ãæ®ãããšã¯éåžžã«å°é£ã§ãã
+èªã¿ãããã ããªãã¯ãã èŠãã ãã§ãã¯ãããããããã§ã©ã®ããã«æ©èœããã®ããã§ã«ããã£ãŠããŸãã
+å°ããªé ããå®æ°ã ãåç¥ã®ããã«ãã¢ã«ãŽãªãºã ã®å®è¡æéã¯ã挞è¿çãªæšå®å€ïŒããã§ã¯ææªã®ã±ãŒã¹ã®ã¿ã§åäœããŸãïŒã ãã§ãªããé ããå®æ°ã®åœ±é¿ãåããŸãã ãã®ã¢ã«ãŽãªãºã ã«ã¯ãéåžžã«å°ããªé ããå®æ°ããããŸãã
çæïŒ
-éåžžã«äœéã ã芧ã®ãšããããaããšããæ°åã®æååã§ããã®ã¢ã«ãŽãªãºã ã¯çŽ10 ^ 9åã®å埩ãè¡ããŸãããããã¯éåžžã«æªãããšã§ãã ããããæååã®é·ãã100,000ã®å Žåã¯ã©ãã§ããããïŒ
1ïŒOïŒN ^ 2ïŒã®æŒžè¿çæ¯ãèããæã€æãå¹³å¡ãªã¢ã«ãŽãªãºã
ã³ãŒãïŒ
void SlowN2::oddCount() { for(int indMiddle = 0; indMiddle < str.length(); ++indMiddle) { int leftBorder = indMiddle - 1, rightBorder = indMiddle + 1; while(leftBorder >= 0 && rightBorder < str.length() && str[leftBorder] == str[rightBorder]) { ++cntPalindromes; --leftBorder; ++rightBorder; } } } void SlowN2::evenCount() { for(int indMiddle = 0; indMiddle < str.length(); ++indMiddle) { int leftBorder = indMiddle, rightBorder = indMiddle + 1; while(leftBorder >= 0 && rightBorder < str.length() && str[leftBorder] == str[rightBorder]) { ++cntPalindromes; --leftBorder; ++rightBorder; } } }
ããã§ããå°ãèå³æ·±ãã æååãšãå¶æ°ããã³å¥æ°ã®é·ãã®åæçšã®2ã€ã®äžæé åããããŸãã ãŸããé åã®ã»ã«iã®æ°å€ã¯ããã€ã³ãiãäžå¿ãšããã©ã€ã³sïŒå ã®ã©ã€ã³ïŒã®åææ°ãæ ŒçŽããŸãã ããªã³ãããŒã ã®é·ããå¥æ°ã®å Žåãäžå¿ã¯ç°¡åã§ãããå¶æ°ã®å Žåã¯ãã€ã³ããã¯ã¹ã§éãã§äžå¿ãå°ãã·ããããŸãïŒã³ãŒããåç §ïŒã çµæã¯ã2ã€ã®é åã®æ°å€ã®åèšã§ãã
ã芧ã®ãšãããããã§ãè€éãªããšã¯äœããããŸããã ãã ãã以åã®ã¢ã«ãŽãªãºã ãããã¯ããã«é«éã«åäœããŸãã ãªãã§ïŒ ãã¹ãŠãã©ã®ããã«æ©èœããããèŠãŠã¿ãŸãããã
ç§ãã¡ã¯ç·ã«æ²¿ã£ãŠèµ°ããæœåšçãªããªã³ãããŒã ã®äžå¿ã·ã³ãã«ããœãŒãããŸãã ãããŠãæåãåãã«ãªããŸã§äžå€®ã®èŠçŽ ããå·Šå³ã«å®è¡ããŸãã ããããç°ãªããšããã«ãããã¯éžæãããèŠçŽ ãäžå¿ãšããããªã³ãããŒã ããªããªãã次ã®ããªã³ãããŒã ããªããªãããšãæå³ããŸãã
ãããŠãæåŸã®æåãçãããªããŸã§å®è¡ããã2çªç®ã®ãã¹ããããã«ãŒãã¯éåžžã«éãå£ããã®ã§ãéåžžã®è¡ã§ã¯éåžžã«é«éã«åäœããŸãïŒè¡ã®åæãéšåæååã®ç·æ°ããã¯ããã«å°ãããšä»®å®ïŒã
ã¡ãœããã®é·æãšçæãèæ ®ããŠãã ããã
é·æïŒ
+ãã¹ãŠã®ã³ãŒãã£ã³ã°ãç°¡åã§ãã ééããããšã¯éåžžã«å°é£ã§ãã
+å°ããªé ããå®æ°
+ã©ã³ãã ãªæååã§ããŸãåäœããŸã
çæïŒ
-ãŸã é·ãé
ãã®æ¹æ³ã®åŸãé ã¯èããèããèãå§ããŸãã ãããŠãããã«ã¢ã€ãã¢ããããŸãïŒ ãããããã®ã¡ãœãããå€æŽãããšãåå埩ã§1æåãã€ã§ã¯ãªããããå°ãã ãäžå€®ã®èŠçŽ ãããžã£ã³ãããããšã«ãªããŸãã ãããŠããã§åœŒãã¯ç§ãã¡ã®å©ãã«æ¥ãŸã...
2ïŒããã·ã¥ã䜿çšããŠãã ããïŒ
ãã®æ¹æ³ã¯å°ãè€éãªã®ã§ãããã«ã³ãŒããæäŸããããã§ã©ã®ãããªéæ³ãèµ·ãã£ãŠããã®ãã説æããããšããŸãïŒãã ããéæ³ã¯ãããŸãããããåãã®éãïŒã
inline long long Hash::getHash(int indLeft, int indRight) const { return prefixHash[indRight] - (indLeft > 0 ? prefixHash[indLeft - 1] : 0); } inline long long Hash::getRevHash(int indLeft, int indRight) const { return suffixHash[indLeft] - (indRight < suffixHash.size() - 1 ? suffixHash[indRight + 1] : 0); } void Hash::PrepareSimpleNumbers() { if(str.length() > simpleNumbers.size()) { size_t oldSize = simpleNumbers.size(); simpleNumbers.resize(str.length()); simpleNumbers[0] = 1LL; for(int i = oldSize; i < simpleNumbers.size(); ++i) simpleNumbers[i] = simpleNumbers[i - 1] * SimpleBase; } } void Hash::CountingPrefixHash() { prefixHash[0] = str[0]; for(int i = 1; i < prefixHash.size(); ++i) { prefixHash[i] = prefixHash[i - 1] + str[i] * simpleNumbers[i]; } } void Hash::CountingSuffixHash() { suffixHash[suffixHash.size() - 1] = str[str.length() - 1]; for(int i = (int) str.length() - 2, j = 1; i >= 0; --i, ++j) { suffixHash[i] = suffixHash[i + 1] + str[i] * simpleNumbers[j]; } } bool Hash::isPalindrome(int indLeft, int indRight) const { return getHash(indLeft, indRight) * simpleNumbers[prefixHash.size() - indRight - 1] == getRevHash(indLeft, indRight) * simpleNumbers[indLeft]; } void Hash::CountingOdd() { for (int i = 0; i < oddCount.size(); i++) { int indLeft = 1, indRight = min(i + 1, static_cast<int> (oddCount.size() - i)); while (indLeft <= indRight) { int middle = (indLeft + indRight) / 2; if (isPalindrome(i - middle + 1, i + middle - 1)) { oddCount[i] = middle - 1; indLeft = middle + 1; } else { indRight = middle - 1; } } } } void Hash::CountingEven() { for (int i = 0; i < evenCount.size(); i++) { int indLeft = 1, indRight = min(i, static_cast<int> (evenCount.size() - i)); while (indLeft <= indRight) { int middle = (indLeft + indRight) / 2; if (isPalindrome(i - middle, i + middle - 1)) { evenCount[i] = middle; indLeft = middle + 1; } else { indRight = middle - 1; } } } } long long Hash::operator()() { PrepareSimpleNumbers(); CountingPrefixHash(); CountingSuffixHash(); CountingOdd(); CountingEven(); for(int i = 0; i < str.length(); ++i) { cntPalindromes += oddCount[i] + evenCount[i]; } return cntPalindromes; }
ãã®æ¹æ³ã®ç°¡åãªæ¬è³ªïŒããªã³ãããŒã ã®äžå¿èŠçŽ ããœãŒããã次ã«äºåæ³ã«ãã£ãŠããªã³ãããŒã ã®æ倧ååŸãèŠã€ããããšããŸãïŒååŸã¯ããã§ã¯äžå¿èŠçŽ ãã極端ãŸã§ã®è·é¢ãæå³ããŸããåããïŒã éžæäžã«ããµãã¹ããªã³ã°ã®IDããã°ããæ¯èŒããå¿ èŠããããŸãã ããã·ã¥ã§ãããè¡ããŸãã 挞è¿æ§ããæ³åã®ãšããïŒNã¯äžå¿èŠçŽ ã®å埩ã«è²»ãããææªã®å Žåã¯åæã®ååŸã®éžæã«è²»ãããlogNãåäœãããã®ããã·ã¥ã䜿çšããŠéšåæååãæ¯èŒããŸãã åèšOïŒNlogNïŒããããŸãããããã¯å®éã«ã¯éåžžã«åªããŠããŸãã
ãã®ã¡ãœããã«ã€ããŠããå°ã詳ãã説æããŸãã
ç§ãã¡ã®æ¹æ³ã¯äœã«åºã¥ããŠããŸããïŒ äžå€®ã®èŠçŽ ã䞊ã¹æ¿ããŠãããäºåæ³ã«ãã£ãŠãã®èŠçŽ ã®äžå¿ãæã€æ倧ã®ããªã³ãããŒã ã®ååŸãéžæãããããæœåšçãªããªã³ãããŒã ã®å·ŠåŽéšåã®ããã·ã¥ããã°ããååŸããæœåšçãªããªã³ãããŒã ã®å³åŽéšåã®ããã·ã¥ãšæ¯èŒããå¿ èŠããããŸãã
ã©ããã£ãŠããã®ïŒ ãœãŒã¹æååã®åãã¬ãã£ãã¯ã¹ãšãµãã£ãã¯ã¹ã®ããã·ã¥ãäºåã«èšç®ããŠã¿ãŸãããã ã³ãŒãã§ã¯ãCountingPrefixHashïŒïŒããã³CountingSuffixHashïŒïŒã¡ãœããããããããããè¡ããŸãã
getHashïŒïŒããã³getRevHashïŒïŒã¡ãœããã䜿çšãããšããã®æ®µéã§èæ ®ãããæœåšçãªåæã®å·Šå³ã®éšåã®ããã·ã¥ããã°ããååŸã§ããŸãã ããã«ãããå·ŠåŽãšå³åŽã«åãããã·ã¥èšç®é¢æ°ã䜿çšã§ããªãçç±ã®åé¡ãçããå ŽåããããŸãã ãã¹ãŠã®çç±ã¯ãåææ§ããã§ãã¯ãããšããå·ŠåŽãå·Šããå³ã«ã2çªç®ãå³ããå·Šã«èªãã ããã§ãã ãããŠãããã·ã¥ãå·Šããå³ãå³ããå·Šã«ç¶æããå¿ èŠããããŸãã
å¯äžã®é£ç¹ã¯æ®ã£ãŠããŸãïŒããã2ã€ã®ããã·ã¥ãæ¯èŒããæ¹æ³ã¯ïŒ ãããŠãisPalindromeïŒïŒã¡ãœããã䜿çšããŠãã®åé¡ã解決ããŸãããã®ã¡ãœããã¯ãããã·ã¥ãåãããŒã¹ã«ãããããããããæ¯èŒããŸãã
åå埩ã®çµæã¯ãäžå¿iã®åææ°ã«ãªããŸãã å¶æ°ããã³å¥æ°ã®é·ãã®åæã«å¯ŸããŠ2åå®è¡ããŸãããã®åé¡ã«å¯Ÿããçãã¯ããã¹ãŠã®oddCounté åãševenCounté åã®åèšã§ãã
ãã®æ¹æ³ã®è©³çŽ°ã«ã€ããŠã¯ã ãã®èšäºãåç §ããŠãã ãã ã
é·æïŒ
+挞è¿çã«ãNlogNã«æžãããŸãããããã¯æå ±ã§ãã ææªã®å Žåã ãããšããšãçè«çã«ã¯ãã€ãåã€ã§ããã
çæïŒ
-æžãã®ã¯ããªãé£ããã§ãã ç°¡åã«ãã°ããŸããŸãã ããã·ã¥ã®åéã§å°ãçè«çãªãã¬ãŒãã³ã°ãå¿ èŠã§ãã
-ã©ã³ãã ãã¹ãã§ãã£ããå®è¡ãããŸãã ããªãèªèº«ã§èŠãããšãã§ããŸãã ãããŠããã¹ãŠã倧ããªé ãããå®æ°ã®ããã§ããããã®èŠçŽ ã®äžå¿ã«åäžã®ããªã³ãããŒã ããªãå Žåã§ããã¢ã«ãŽãªãºã ã¯logNãžã£ã³ããè¡ããããã«ã¯ãã¹ãŠæéãããããŸãã
-è¡çªã ã芧ã®ãšãããç§ã®ãœãŒã¹ã³ãŒãã¯ããã·ã¥ã䜿çšããŠããŸããããã·ã¥ã¯éåžžãããã°ã©ãã³ã°ãªãªã³ããã¯ã§äœæãããŸãïŒã¯ããã¯ããç§ã¯ãããå°ã䜿çšããŠããŸããïŒã ãã®ããã競æäŒã§ã¯ãã®æ¹æ³ãããè¡šããŠããŸãã å人çã«ã¯ãè¡çªã¯ãããŸããã§ããã ããããç§ã¯ãã®ããã·ã¥ïŒç¹ã«ãThue-Morseæååã䜿çšããæ¹æ³ïŒãéãã«åããæ¹æ³ãç¥ã£ãŠããŸãã ãã®ãã¹ãã§å£ããŠããªãããã«èŠãããã£ããããããã·ã¥ããããšèããããšããããŸãããæ å ±ã¯ä¿¡é Œã§ããŸããã ãã®ãããè¡çªã«ã¯æ³šæããŠãã ããã
ãããŠãè¡çªè£æ£ãªãã§100ïŒ ã®ãœãªã¥ãŒã·ã§ã³ãå¿ èŠã§ãç°ãªãæ¹æ³ã§ããã·ã¥ãå ¥åãããªã©ã®å Žåã¯ã©ãã§ããããã
3ïŒãããã«ãŒã¢ã«ãŽãªãºã
ã³ãŒãïŒ
//Find palindroms like 2*N+1 void Manacker::PalN2() { int leftBorder = 0, rightBorder = -1, tempMirror;//start digits for algortihm for(int i = 0; i < str.length(); ++i) { tempMirror = (i > rightBorder ? 0 : std::min(ansPalN2[leftBorder + rightBorder - i], rightBorder - i)) + 1;//find mirror of current index while(i + tempMirror < str.length() && i - tempMirror >= 0 && str[i - tempMirror] == str[i + tempMirror])//increase our index { ++tempMirror; } ansPalN2[i] = --tempMirror; if(i + tempMirror > rightBorder)//try to increase our right border of palindrom { leftBorder = i - tempMirror; rightBorder = i + tempMirror; } } } void Manacker::Pal2() { int leftBorder = 0, rightBorder = -1, tempMirror; for(int i = 0; i < str.length(); ++i) { tempMirror = (i > rightBorder ? 0 : std::min(ansPal2[leftBorder + rightBorder - i + 1], rightBorder - i + 1)) + 1; while(i + tempMirror - 1 < str.length() && i - tempMirror >= 0 && str[i - tempMirror] == str[i + tempMirror - 1]) { ++tempMirror; } ansPal2[i] = --tempMirror; if(i + tempMirror - 1 > rightBorder) { leftBorder = i - tempMirror; rightBorder = i + tempMirror - 1; } } }
ããã§ãããã·ã¥ã䜿çšããŠNlogNã®ããã·ã¥ã¢ã«ãŽãªãºã ãååŸããŸããã ãããããã£ãšéããããã§ãã ç·åœ¢ã®ãã®ã欲ããã ãããŠãããã§Manakerã¢ã«ãŽãªãºã ã¯æ¥ãã§å©ããŠãããŸãïŒãªã³ã¯ã«ãã£ãŠJavaã§ã®ã¢ã«ãŽãªãºã ã®å®è£ ãèŠãããšãã§ããŸãïŒãããã¯ç·åœ¢ã§ããã ãã§ãªããéåžžã«å°ããªé ããå®æ°ãæã¡ãé床ã«ãã©ã¹ã®åœ±é¿ãäžããŸãã ãã®ãã°ããããªã³ã¯ã®æ¹äœã«ã€ãªããã®ã§ããã®æ¹æ³ã«ã€ããŠã¯è©³ãã説æããŸããïŒç§ã¯ãã®ãªã³ã¯ããã¢ã«ãŽãªãºã ãåŠã³ãŸããïŒã ããã§ãå°ãæ¹ããŠèª¬æããŸãã
ã¢ã«ãŽãªãºã ã¯ãè¡ããšã«åŠçããè¡ã®å³ç«¯ã®åæããµããŒãããããšã§ãã ãããŠãåå埩ã§ãçŸåšã®èŠçŽ ã¯å³ç«¯ã®åæã®å¢çå ã«ãããã©ããã§ãã ããã§ããå Žåãã€ã³ããã¯ã¹ã䜿çšããç°¡åãªæäœã«ããã以åã«èšç®ãããå€ããçããæœåºã§ããŸãã ããã§ãªãå Žåã¯ããã®ã¬ãã¥ãŒã®ãã©ã°ã©ã1ïŒã§èª¬æãããŠããã¢ã«ãŽãªãºã ãšãŸã£ããåãã¢ã«ãŽãªãºã ã«åŸããŸããã·ã³ãã«ããšã«ç§»åããäžå¿ã«å¯ŸããŠãã©ãŒèŠçŽ ãæ¯èŒããŸãã ããããçããéãè¡ããŸãã ãããŠããã®åŸã«èŠã€ãã£ãå³ç«¯ã®åæã®å¢çç·ãæŽæ°ããããšãå¿ããªãã§ãã ããã ããã¯ç°¡åã§ãã èšäºã®èœãšãç©Žã®ããã€ãã«ã€ããŠèªãããšãã§ããŸãã
ä»ã«èå³æ·±ãã®ã¯ãïŒãªãªã³ããã¯ããã°ã©ãã³ã°ã®ïŒã³ã³ãã¹ãã§è§£æ±ºãããã¹ãŠã®åé¡ã§ããã®ã¢ã«ãŽãªãºã ã§ååã§ããã èªå® ã§NåæžããŠããã§ã«æèšããŠããã°ãæžãã®ã¯ãšãŠãç°¡åã§ãã
é·æïŒ
+ããªãçãã³ãŒãã
+éåžžã«é«éã«åäœããŸãã OïŒNïŒã®æŒžè¿çãªæ¯ãèãã ãã§ãªããå°ããªé ããå®æ°ã§ããããŸãã
çæïŒ
-ãã®ã¢ã«ãŽãªãºã èªäœãèãåºãã®ã¯ããã»ã©ç°¡åã§ã¯ãããŸãã
-ã³ãŒããæžããšãã«æ³šæãæ ããšãããããçš®é¡ã®ã€ã³ããã¯ã¹ã§æ··ä¹±ããå¯èœæ§ããããŸã
ãã®åé¡ãç·åœ¢æéã§è§£æ±ºããä»ã®æ¹æ³ã¯ãããŸããïŒ
4ïŒããªã³ãããŒã ããªãŒ
èæ¯ã®ãããã ãã®æ¯èŒçæ°ããããŒã¿æ§é ã¯ãMikhail Rubinchik rumi13ã«ãã£ãŠçºèŠããããããã¶ãŽã©ãŒãã¯ãã¬ãŒãã³ã°ãã£ã³ãã§çºè¡šãããŸããã ãã®æ§é ã¯ãäžæ¹ã§åçŽã§ãããä»æ¹ã§ããªã³ãããŒã ã®ããªãåºç¯å²ã®åé¡ãè¿ éã«è§£æ±ºãããšããç¹ã§éåžžã«èå³æ·±ããã®ã§ãã ãããŠæãéèŠãªããš-ããã¯ããªããéåžžã«åçŽã«é£ç¶ããŠããªã³ãããŒã ã®æ°ãOïŒNïŒãšããŠæ°ããããšãå¯èœã«ããŸãïŒããããããªã³ãããŒã ããªãŒèªäœã¯ãã®ããã«èšèšãããã®ã§ã¯ãªããããªã³ãããŒã ã®ããæ·±å»ãªã¿ã¹ã¯ã®ããã«èšèšããããšæããŸãïŒã
ã³ãŒãïŒ
PalindromicTree::PalindromicTree(const std::string& s) : FindPalindrome(s) { initTree(); } PalindromicTree::~PalindromicTree() { for(int i = 0;i < pullWorkNodes.size(); ++i) { delete pullWorkNodes[i]; } } void PalindromicTree::initTree() { root1 = new Node; root1->len = -1; root1->sufflink = root1; root2 = new Node; root2->len = 0; root2->sufflink = root1; suff = root2; pullWorkNodes.push_back(root1); pullWorkNodes.push_back(root2); } void PalindromicTree::findAddSuffix(Node* &cur, int pos, int& curlen) { while (true) { curlen = cur->len; if (pos - 1 - curlen >= 0 && str[pos - 1 - curlen] == str[pos]) { break; } cur = cur->sufflink; } } void PalindromicTree::makeSuffixLink(Node* &cur, int pos, int& curlen,int let) { while (true) { cur = cur->sufflink; curlen = cur->len; if (pos - 1 - curlen >= 0 && str[pos - 1 - curlen] == str[pos]) { suff->sufflink = cur->next[let]; break; } } } void PalindromicTree::addLetter(int pos) { Node* cur = suff; int let = str[pos] - 'a', curlen = 0; findAddSuffix(cur, pos, curlen); if (cur->next[let] != nullptr) { suff = cur->next[let]; return; } suff = new Node; pullWorkNodes.push_back(suff); suff->len = cur->len + 2; cur->next[let] = suff; if (suff->len == 1) { suff->sufflink = root2; suff->num = 1; return; } makeSuffixLink(cur, pos, curlen, let); suff->num = 1 + suff->sufflink->num; } long long PalindromicTree::operator ()() { for (int i = 0; i < str.length(); ++i) { addLetter(i); cntPalindromes += suff->num - 1; } return cntPalindromes; }
ç¹°ãè¿ããŸããããã®ã¢ã«ãŽãªãºã ã®æ¬è³ªãç°¡åã«èª¬æããŸãã ãã®ãã°ãããèšäºã§ããã詳现ãªèª¬æãèŠã€ããããšãã§ããŸãã
ã ãããããªãŒã®ã¢ã€ãã¢ã ããªã³ãããŒã èªèº«ã ããããªãŒã®æäžéšã«ãããŸãïŒãaãããbãããabaããªã©ã ããªã³ãããŒã ãä¿åããã®ã§ã¯ãªããããã«æ¥ãé ç¹ãšäž¡åŽã«è¿œå ããã·ã³ãã«ãä¿åããã ãã§ãã ãŸããã¢ã«ãŽãªãºã ã®äŸ¿å©ãªå®è£ ã®ããã«ã2ã€ã®ãããŒé ç¹ããããŸãã
ããããèå³æ·±ãããªãŒã®ããã«ãæ¥å°ŸèŸãªã³ã¯ããããŸãã æ¥å°ŸèŸãªã³ã¯ã¯é ç¹ã«ã€ãªãããŸããããã¯ããªã³ãããŒã ã§ãããïŒé ç¹ã«ããªã³ãããŒã ããæ ŒçŽãããŠããªãããïŒããã®é ç¹ã®æ倧ã®é©åãªæ¥å°ŸèŸã§ãã ã€ãŸãããabaãã®äžéšãããªã³ã¯ããaãã®äžéšã«ã€ãªãããŸãã
次ã«ãããªãŒã«æåã1ã€ãã€è¿œå ããŸãã ãããŠãããªãŒã®ããªãããŒãªããã€ã¹ãšè¿œå ã®ååž°æäœïŒããã³ééãããµãã£ãã¯ã¹ãªã³ã¯ïŒã®ãããã§ãããªãŒå šäœãæŽæ°ããŸãã
ããã¯ç°¡åã§ããäžèšã®ãªã³ã¯ã§è©³çŽ°ãèªãã§ãã ããïŒè±èªãæããªãå ŽåïŒ
é·æïŒ
+以åã«ããªãŒã§äœæ¥ããããšãããå Žåããã®èããç解ããã®ã¯éåžžã«ç°¡åã§ãã
+ããªã³ãããŒã ã«é¢ããå¹ åºãã¿ã¹ã¯ã解決ã§ããŸã
çæïŒ
-Manakerã¢ã«ãŽãªãºã ãããå®è¡é床ãé ããªããŸãã
-ããªãã¯ãã°ã眮ãããšãã§ããŸãã ããããçŽç²ã«äž»èŠ³çã§ãããããåãManakerã¢ã«ãŽãªãºã ãããããã§è¡ãã®ã¯å°é£ã§ãã
æšã®å©ããåããŠããã®åé¡ã«å¯Ÿããå¥ã®è§£æ±ºçãããããšãèšåãã䟡å€ããããŸãã ããã¯ããµãã£ãã¯ã¹ããªãŒãšé«éLCAã¢ã«ãŽãªãºã ïŒOïŒNïŒååŠçããã³OïŒ1ïŒèŠæ±ãžã®å¿çã«å¯ŸããŠæ©èœããŸãããã¡ã©ãŒã³ã«ãã³ãã³ããŒã¢ã«ãŽãªãºã ïŒã䜿çšããŠæ§æãããŸãã ããããå®éã«ã¯äœ¿çšãããŸãããããªãè€éã§ãéåžžã«å€§ããªé ãããå®æ°ãæã£ãŠããããã§ãã åŠåçé¢å¿ã®å¯èœæ§ãæãé«ãã
ã¢ã«ãŽãªãºã ã«ã€ããŠä»ã«èå³æ·±ããã®ã¯ãããŸããïŒ ããã§ããã¡ã¢ãªæ¶è²»ãšçšŒåæéã
githubã§ã¯ãã©ã³ãã ãªæååãçæããããªã³ãããŒã ãæ¢ããã¹ãã³ãŒããããŠã³ããŒãããããšãã§ããŸãã
ç§ã®ãã¹ãã§ã¯ãäºæ³ã©ãããã¢ã«ãŽãªãºã çªå·0ã¯éåžžã«é ãããšã瀺ãããŸããã ãªãŒããŒã¯ããæ³åã®ãšããããããã«ãŒã¢ã«ãŽãªãºã ã§ãã ããããæãèå³æ·±ãã®ã¯ãOïŒN ^ 2ïŒã®ã¢ã«ãŽãªãºã ã¯ãOïŒNlogNïŒã®ããã·ã¥ã䜿çšããŠã¢ã«ãŽãªãºã ãçŽ2åäžåãããšã§ããããã¯ãã¢ã«ãŽãªãºã ãåäžã®ã¢ã«ãŽãªãºã ã®æŒžè¿çåäœã«ãã£ãŠæž¬å®ãããªãããšãå床蚌æããŸã ããã¯ãã¯ãªããã³ã°ã¢ã«ãŽãªãºã çªå·1ã®æ§è³ªãšãããã·ã¥ã䜿çšããã¡ãœããã«ã¯ãªãããã§ãã ããªã³ãããŒã ããªãŒã«é¢ããŠã¯ãæ°ããé ç¹ããšã«ã¡ã¢ãªãå²ãåœãŠãå¿ èŠããããããäž»ã«ã¡ã¢ãªæäœã®ããã«Manakerã«å€±ãããŸãã ãã ããããšãã°ããã¬ãŒã¹ã¡ã³ãä»ãã®æ°èŠã䜿çšããå Žåãã®ã£ããã¯çããªããŸãã
ãã¹ãŠã®ã¢ã«ãŽãªãºã ã¯ãå ¥åããŒã¿ã®ãµã€ãºããç·åœ¢ã«ã¡ã¢ãªãæ¶è²»ããŸãã
ããã§ã¬ãã¥ãŒã¯çµäºã§ãã ããªããããªãèªèº«ã®ããã«äœãæ°ããããšãåŠã³ãå°ãªããšãå°ãèå³ãæã£ãŠããããšãé¡ã£ãŠããŸãïŒ Githubã®å ¬éãªããžããªã§ãã¹ãŠã®ãœãŒã¹ãèŠã€ããããšãã§ããŸãã
PSïŒèª€åãäžæ£ç¢ºãããŸãã¯è¿œå äºé ã«æ°ä»ããå Žåã¯ãã³ã¡ã³ãã®ç»é²ã解é€ããPMã«æžã蟌ãã§ãã ããã
PPSïŒã³ã¡ã³ãã§è³ªåããŠãã ãã-ç§ã®èœåãååã§ããã°çããããšããŸãã
ãã®èšäºãèªãã åŸã«ããªãã«èå³ããããããããªã䟿å©ãªãªã³ã¯ïŒèšäºèªäœãããæããå¯èœæ§ããããããããã€ãã®ãªã³ã¯ã¯ç¹°ãè¿ããããããããŸããïŒïŒ
0ïŒ åæãšã¯
1ïŒManakerã¢ã«ãŽãªãºã ïŒ Wiki ã Codeforces ã e-maxx
2ïŒããã·ã¥ãšãã®é©çšã«ã€ããŠå°ãïŒ e-maxx ã Habrahabr
3ïŒCodeforceã®ããã·ã¥ã®ãããã¯ã«é¢ããè°è«ïŒ tyts
4ïŒThue Morseã®è¡ïŒåèªïŒïŒ one ã two
5ïŒåæããªãŒã«é¢ããèšäºïŒ è¯ã説æ ã ã³ãŒããã©ãŒã¹
6ïŒããªã³ãããŒã çªå·ã®æ€çŽ¢ã«é¢ããå¥ã®ã·ãªãŒãºã®èšäºã¯æ¬¡ã®ãšããã§ãã