結果

問題 No.3136 F,B in FizzBuzzString16
ユーザー ID 21712
提出日時 2025-04-28 17:41:33
言語 Java
(openjdk 23)
結果
AC  
実行時間 195 ms / 2,000 ms
コード長 4,904 bytes
コンパイル時間 5,708 ms
コンパイル使用メモリ 87,632 KB
実行使用メモリ 44,444 KB
最終ジャッジ日時 2025-04-28 17:41:47
合計ジャッジ時間 12,445 ms
ジャッジサーバーID
(参考情報)
judge2 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 7
other AC * 32
権限があれば一括ダウンロードができます

ソースコード

diff #

import java.util.*;

// F,B in FizzBuzzString16
// author: Leonardone @ NEETSDKASU

public class Solution {

    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);

        long X = scanner.nextLong();
        long Y = scanner.nextLong();

        long answer = new Solution().solve(X, Y);

        System.out.println(answer);
    }

    long solve(long X, long Y) {
        long a = CountFBtoPosition(Y);
        long b = CountFBtoPosition(X - 1L);
        long answer = a - b;
        return answer;
    }

    String FizzBuzz16(long i) {
        if (i % 15L == 0L) {
            return "FizzBuzz";
        } else if (i % 3L == 0L) {
            return "Fizz";
        } else if (i % 5L == 0L) {
            return "Buzz";
        } else {
            return String.format("%X", i);
        }
    }

    // FizzBuzzString16(1000000000000)の1文字目からv文字目までのFとBの個数の合計を求める
    long CountFBtoPosition(long v) {
        if (v < 1L) {
            return 0L;
        }
        long N = FindNfromPosition(v);
        long count = CountFBofFizzBuzzString16(N - 1L);
        int length = (int)(v - FizzBuzzString16Length(N - 1L));
        String s = FizzBuzz16(N);
        for (int i = 0; i < length; i++) {
            if (s.charAt(i) == 'F' || s.charAt(i) == 'B') {
                count++;
            }
        }
        return count;
    }

    // FizzBuzzString16(1000000000000)のv文字目において
    //   FizzBuzzString16Length(N - 1) < v <= FizzBuzzString16Length(N)
    // となるNを求める
    long FindNfromPosition(long v) {
        long lower = 0L;
        long upper = 1000000000001L;
        while (lower + 1L < upper) {
            long middle = (lower + upper) / 2L;
            long count = FizzBuzzString16Length(middle);
            if (count < v) {
                lower = middle;
            } else {
                upper = middle;
            }
        }
        return upper;
    }

    // FizzBuzzString16(v)の文字列長を求める
    long FizzBuzzString16Length(long v) {
        if (v < 0L) {
            return 0L;
        }

        long length = 0L;
        long digit_size = 1L;

        while (true) {
            long lower = (long)Math.pow(16.0, digit_size - 1.0);
            if (lower > v) {
                return length;
            }
            long upper = Math.min(v, lower * 16L - 1L);

            long count15 = (upper / 15L) - ((lower - 1L) / 15L);
            long count3 = (upper / 3L) - ((lower - 1L) / 3L);
            long count5 = (upper / 5L) - ((lower - 1L) / 5L);
            long count = upper - (lower - 1L);

            long fizzbuzz = 8L * count15;
            long fizz = 4L * (count3 - count15);
            long buzz = 4L * (count5 - count15);
            long hex_number = digit_size * (count - (count3 + count5 - count15));
            length += fizzbuzz + fizz + buzz + hex_number;

            digit_size++;
        }
    }

    // FizzBuzzString16(v)のFとBの個数の合計を求める
    long CountFBofFizzBuzzString16(long v) {
        if (v < 1L) {
            return 0L;
        }

        // 桁の組み合わせの総数
        // DP[桁数][桁の和][F,Bの個数]
        long[][][] DP = new long[10][150+16][11];

        // DPの初期値の設定
        {
            int b = 0, c = 0;
            for (int a = 0; a < 10; a++) {
                int d = Character.digit(String.format("%010X", v).charAt(a), 16);
                for (int t = 0; t < d; t++) {
                    if (t == 0xB) {
                        DP[a][b+t][c+1] += 1L;
                    } else {
                        DP[a][b+t][c] += 1L;
                    }
                }
                if (d == 0xF || d == 0xB) {
                    c++;
                }
                b += d;
            }
            DP[9][b][c] += 1L;
        }

        for (int a = 0; a < 9; a++) {
            for (int b = 0; b < 150; b++) {
                for (int c = 0; c < 10; c++) {
                    for (int d = 0x0; d < 0x10; d++) {
                        if (d == 0xF || d == 0xB) {
                            DP[a+1][b+d][c+1] += DP[a][b][c];
                        } else {
                            DP[a+1][b+d][c] += DP[a][b][c];
                        }
                    }
                }
            }
        }

        long count = 0L;
        for (int b = 1; b < 150; b++) {
            for (int c = 0; c < 11; c++) {
                if (b % 15 == 0) {
                    count += 2L * DP[9][b][c];
                } else if (b % 3 == 0) {
                    count += DP[9][b][c];
                } else if (b % 5 == 0) {
                    count += DP[9][b][c];
                } else {
                    count += (long)c * DP[9][b][c];
                }
            }
        }

        return count;
    }
}
0