結果

問題 No.2846 Birthday Cake
ユーザー GOTKAKOGOTKAKO
提出日時 2024-08-23 23:08:22
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 1,381 ms / 2,000 ms
コード長 5,034 bytes
コンパイル時間 2,437 ms
コンパイル使用メモリ 220,496 KB
実行使用メモリ 45,656 KB
最終ジャッジ日時 2024-08-23 23:08:42
合計ジャッジ時間 19,702 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
6,816 KB
testcase_01 AC 2 ms
6,944 KB
testcase_02 AC 528 ms
26,200 KB
testcase_03 AC 1 ms
6,944 KB
testcase_04 AC 2 ms
6,940 KB
testcase_05 AC 712 ms
30,988 KB
testcase_06 AC 881 ms
35,640 KB
testcase_07 AC 1,070 ms
39,536 KB
testcase_08 AC 1,250 ms
42,276 KB
testcase_09 AC 1,323 ms
44,056 KB
testcase_10 AC 1,339 ms
45,040 KB
testcase_11 AC 1,381 ms
45,516 KB
testcase_12 AC 518 ms
28,688 KB
testcase_13 AC 864 ms
40,364 KB
testcase_14 AC 6 ms
6,944 KB
testcase_15 AC 62 ms
8,960 KB
testcase_16 AC 177 ms
16,128 KB
testcase_17 AC 965 ms
43,736 KB
testcase_18 AC 1,376 ms
45,656 KB
testcase_19 AC 2 ms
6,944 KB
testcase_20 AC 4 ms
6,940 KB
testcase_21 AC 2 ms
6,940 KB
testcase_22 AC 14 ms
6,940 KB
testcase_23 AC 9 ms
6,940 KB
testcase_24 AC 965 ms
43,324 KB
testcase_25 AC 2 ms
6,944 KB
testcase_26 AC 17 ms
6,940 KB
testcase_27 AC 28 ms
6,944 KB
testcase_28 AC 2 ms
6,944 KB
testcase_29 AC 59 ms
8,960 KB
testcase_30 AC 2 ms
6,944 KB
testcase_31 AC 4 ms
6,940 KB
testcase_32 AC 542 ms
22,512 KB
testcase_33 AC 960 ms
43,332 KB
testcase_34 AC 154 ms
15,352 KB
testcase_35 AC 177 ms
16,116 KB
testcase_36 AC 574 ms
28,916 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;

struct frac{ //最終的に分子分母64bitに収まる計算のみ.
    public:
    long long n,d;
    frac() : n(0),d(1){}
    frac(long long v) : n(v),d(1) {}
    frac(long long a,long long b,bool redu = true){
        assert(b != 0);
        if(redu) reduce(a,b);
        n = a,d = b; 
    }
    private:
    long long gcd(long long a,long long b){
        if(a%b == 0) return b;
        return gcd(b,a%b);
    } 
    long long gcd128(long long a,long long b){ //絶対値gcd128.
        if(b == 0) return abs(a);
        return gcd(abs(a),abs(b));
    }
    void reduce(long long &a,long long &b){ //約分.
        if(b < 0) a = -a,b = -b;
        long long div = gcd128(a,b);
        a /= div; b /= div;
    }
    public:
    //計算量 O(logmax(d,b.d)).
    friend frac operator+(const frac &b){return b;}
    friend frac operator-(const frac &b){return frac(-b.n,b.d,false);}
    friend frac operator+(const frac &a,const frac &b){
        return frac((long long)a.n*b.d+(long long)b.n*a.d,(long long)a.d*b.d);
    } 
    friend frac operator-(const frac &a,const frac &b){
        return frac((long long)a.n*b.d-(long long)b.n*a.d,(long long)a.d*b.d);
    }
    friend frac operator*(const frac &a,const frac &b){
        long long g1 = std::gcd(a.n,b.d),g2 = std::gcd(a.d,b.n);
        return frac((a.n/g1)*(b.n/g2),(a.d/g2)*(b.d/g1),false);
    }
    friend frac operator/(const frac &a,const frac &b){
        assert(b.n != 0);
        long long g1 = std::gcd(a.n,b.n),g2 = std::gcd(a.d,b.d);
        if(b.n < 0) return frac((-a.n/g1)*(b.d/g2),(a.d/g2)*(-b.n/g1));
        else return frac((a.n/g1)*(b.d/g2),(a.d/g2)*(b.n/g1));
    }
    friend bool operator==(const frac &a,const frac &b){return a.n==b.n && a.d==b.d;}
    friend bool operator!=(const frac &a,const frac &b){return a.n!=b.n || a.d!=b.d;}
    friend bool operator>(const frac &a,const frac &b){return (long long)a.n*b.d > (long long)b.n*a.d;}
    friend bool operator>=(const frac &a,const frac &b){return (long long)a.n*b.d >= (long long)b.n*a.d;}
    friend bool operator<(const frac &a,const frac &b){return (long long)a.n*b.d < (long long)b.n*a.d;}
    friend bool operator<=(const frac &a,const frac &b){return (long long)a.n*b.d <= (long long)b.n*a.d;}
 
    frac &operator=(const frac &b) = default;
    frac operator+=(const frac &b){return *this=*this+b;}
    frac operator-=(const frac &b){return *this=*this-b;}
    frac operator*=(const frac &b){return *this=*this*b;}
    frac operator/=(const frac &b){return *this=*this/b;}
    frac operator++(int){*this += frac(1); return *this;}
    frac operator--(int){*this -= frac(1); return *this;}
 
    double decimal(){return (n+0.0)/d;}
    long double decimall(){return ((long double)n)/d;}
    long long num(){return n;} long long den(){return d;}
    long long floor(){return n<0?(n+1)/d-1:n/d;}
    long long ceil(){return n>0?(n-1)/d+1:n/d;}
    frac inv(){return frac(n>=0?d:-d,n>=0?n:-n,false);}
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int K,N; cin >> K >> N;
    vector<__int128_t> fac(K+1);
    fac.at(0) = 1;
    for(int i=1; i<=K; i++) fac.at(i) = fac.at(i-1)*i;
    vector<frac> mindec(K+1);
    for(int i=1; i<=K; i++) mindec.at(i) = frac(i,N);

    vector<long long> lcm(N+1);
    long long lc = 1;
    for(int i=N; i>=1; i--) lc = lc*i/gcd(lc,i),lcm.at(i) = lc;

    long long inf = 1000000000;
    int left = N/2,right = (N-left);
    vector<unordered_map<long long,__int128_t>> dp1(K+1),dp2(K+1);
    dp1.at(0)[inf+1] += fac.at(K); dp2.at(0)[inf+1] += fac.at(K);

    for(int i=1; i<=left; i++){
        frac dec(1,i);
        for(int k=K-1; k>=0; k--){
            for(auto &[ke,v] : dp1.at(k)){
                frac now(ke/inf,ke%inf);
                for(int l=1; l<=K-k; l++){
                    now -= dec;
                    if(now < 0 || now.d > 20000) break;
                    dp1.at(k+l)[now.n*inf+now.d] += v/fac.at(l);
                }
            }
        }
    }
    for(int i=left+1; i<=N; i++){
        frac dec(1,i);
        for(int k=K-1; k>=0; k--){
            for(auto &[ke,v] : dp2.at(k)){
                frac now(ke/inf,ke%inf);
                for(int l=1; l<=K-k; l++){
                    now -= dec;
                    if(now < 0 || now.d > 20000) break;
                    dp2.at(k+l)[now.n*inf+now.d] += v/fac.at(l);
                }
            }
        }
    }
    
    long long answer = 0;
    for(int i=0; i<=K; i++){
        for(auto &[ke,v] : dp1.at(i)){
            frac now(ke/inf,ke%inf);
            now = frac(1)-now;
            auto itr = dp2.at(K-i).find(now.n*inf+now.d);
            if(itr != dp2.at(K-i).end()){
                __int128_t v2 = itr->second;
                for(int k=1; k<=K; k++){
                    int div = k;
                    int g = gcd(div,v);
                    div /= g; v /= g; v2 /= div;
                }
                answer += v*v2;
            }
        }
    }
    cout << answer << endl;
}
0