package main import ( "bufio" "os" "strconv" ) // --------------------------------------------------------------------------- // 入出力 // 標準入力を自前のバッファで少しずつ読み、1 トークンずつ切り出す。 // - トークン長に上限がない(組み立て先の rtok が伸びるだけ) // - 区切りが来た時点で返るので、手で打ち込む場合も Ctrl+D が要らない // - 入力全体をメモリに載せない // - 空白・タブ・改行はすべて同じ区切り。末尾の改行の有無は結果に影響しない // - 単語読み(ri/rs)と行読み(rline)を混ぜてよい // 出力は必ず wr 経由。main の defer で 1 度だけ Flush する。 // --------------------------------------------------------------------------- var ( rbuf = make([]byte, 1<<16) // 標準入力の読み込みバッファ rpos int // rbuf の次に読む位置 rend int // rbuf に入っている有効バイト数 rtok []byte // トークンの組み立て先。使い回す wr = bufio.NewWriter(os.Stdout) ) // 解答は solve() に書く。main は触らないこと。 // main に直接書くと、ここにあった defer wr.Flush() を消してしまい、 // 出力が 1 文字も出ないまま WA になる事故が起きる。 func main() { defer wr.Flush() // 必ず先頭。途中で return しても出力されるようにする。 solve() } func solve() { _ = ri() S := rs() count := 0 l := len(S) - 5 P := "HAPPY" for i, s := range S[l : l+5] { if P[i] != byte(s) { count++ } } for i := 0; i < l-5; i++ { if S[i:i+5] == "HAPPY" { count++ } } outln(count) } // --- 入力 ------------------------------------------------------------------- // fill は rbuf を補充する。もう読めなければ false(EOF)。 func fill() bool { for { n, err := os.Stdin.Read(rbuf) if n > 0 { rpos, rend = 0, n return true } if err != nil { return false } // n == 0 かつ err == nil は何も起きていないのと同じなので読み直す。 } } // readByte は 1 バイト読む。EOF なら ok が false。 func readByte() (byte, bool) { if rpos == rend && !fill() { return 0, false } c := rbuf[rpos] rpos++ return c, true } // skipSpace は空白類を読み飛ばし、最初の非空白バイトを返す。 func skipSpace() (byte, bool) { for { c, ok := readByte() if !ok { return 0, false } if c > ' ' { return c, true } } } // rbs はトークンを 1 つ読んで []byte で返す。 // 戻り値は使い回しのバッファを指すので、次の読み取りで内容が変わる。 // あとで保持したいなら rs() を使うか、append でコピーする。 func rbs() []byte { c, ok := skipSpace() if !ok { return nil } rtok = append(rtok[:0], c) for { c, ok = readByte() if !ok || c <= ' ' { break } rtok = append(rtok, c) } return rtok } // rs はトークンを 1 つ読む(文字列としてコピーする)。 func rs() string { return string(rbs()) } // ri は整数を 1 つ読む。数字以外が混ざっていたら panic して気づけるようにする。 func ri() int { c, ok := skipSpace() if !ok { panic("入力を読みすぎている (EOF)") } neg := false switch c { case '-': neg = true c, ok = readByte() case '+': c, ok = readByte() } if !ok || c <= ' ' { panic("符号のあとに数字がない") } n := 0 for { if c < '0' || c > '9' { panic("整数として読めない文字: " + string(c)) } n = n*10 + int(c-'0') var more bool c, more = readByte() if !more || c <= ' ' { break } } if neg { return -n } return n } // rf は浮動小数を 1 つ読む。 func rf() float64 { f, err := strconv.ParseFloat(string(rbs()), 64) if err != nil { panic(err) } return f } // ri2 / ri3 は整数をまとめて読む。`a, b := ri2()` のように使う。 func ri2() (int, int) { return ri(), ri() } func ri3() (int, int, int) { return ri(), ri(), ri() } // ris は整数を n 個読む。 func ris(n int) []int { a := make([]int, n) for i := range a { a[i] = ri() } return a } // rss はトークンを n 個読む。 func rss(n int) []string { a := make([]string, n) for i := range a { a[i] = rs() } return a } // rgrid は h 行の文字列グリッドを読む。g[i][j] でアクセスする。 // 行ごとに確保するので、書き換えても他の行に影響しない。 func rgrid(h int) [][]byte { g := make([][]byte, h) for i := range g { g[i] = append([]byte(nil), rbs()...) } return g } // rline は次の 1 行を、行内の空白を保ったまま返す。 // 直前のトークンの後ろに残っている改行と、空行は読み飛ばす。 func rline() string { var c byte var ok bool for { c, ok = readByte() if !ok { return "" } if c != '\n' && c != '\r' { break } } rtok = append(rtok[:0], c) for { c, ok = readByte() if !ok || c == '\n' { break } rtok = append(rtok, c) } if n := len(rtok); n > 0 && rtok[n-1] == '\r' { // CRLF の \r を落とす rtok = rtok[:n-1] } return string(rtok) } // --- 出力 ------------------------------------------------------------------- // obuf は数値を文字列化するときの作業領域。使い回して確保を避ける。 var obuf []byte func writeInt(x int) { obuf = strconv.AppendInt(obuf[:0], int64(x), 10) wr.Write(obuf) } // outln は値を空白区切りで並べて改行する。 func outln(a ...any) { for i, v := range a { if i > 0 { wr.WriteByte(' ') } writeAny(v) } wr.WriteByte('\n') } // outis は整数スライスを空白区切り 1 行で出力する。 func outis(a []int) { for i, v := range a { if i > 0 { wr.WriteByte(' ') } writeInt(v) } wr.WriteByte('\n') } // yesno は真偽を Yes / No で出力する。 func yesno(ok bool) { if ok { wr.WriteString("Yes\n") } else { wr.WriteString("No\n") } } func writeAny(v any) { switch x := v.(type) { case int: writeInt(x) case int64: obuf = strconv.AppendInt(obuf[:0], x, 10) wr.Write(obuf) case string: wr.WriteString(x) case []byte: wr.Write(x) case byte: wr.WriteByte(x) case float64: obuf = strconv.AppendFloat(obuf[:0], x, 'f', 10, 64) wr.Write(obuf) case bool: if x { wr.WriteString("true") } else { wr.WriteString("false") } default: panic("outln: 対応していない型") } } // --- よく使う小物 ----------------------------------------------------------- // min / max は Go 1.21 以降の組み込みを package スコープで覆う。 // AtCoder 側が Go 1.20 系でも同じコードが通るように、あえて自前で定義している。 type number interface { ~int | ~int64 | ~float64 } func min[T number](a, b T) T { if a < b { return a } return b } func max[T number](a, b T) T { if a > b { return a } return b } // chmin / chmax は代入して更新できたら true を返す。DP の更新で使う。 func chmin[T number](a *T, b T) bool { if b < *a { *a = b return true } return false } func chmax[T number](a *T, b T) bool { if b > *a { *a = b return true } return false } func abs(a int) int { if a < 0 { return -a } return a }