Submission

Status:
PPPPPPPPPPPPPPPP

Score: 160

User: pppppppppppp

Problemset: Chocolate

Language: cpp

Time: 0.088 second

Submitted On: 2025-04-17 09:08:08

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
static const ll MOD = 1000000007;

// fast power j^e
inline __int128 ipow128(ll j, int e) {
    __int128 r = 1, b = j;
    while (e) {
        if (e & 1) r *= b;
        b *= b;
        e >>= 1;
    }
    return r;
}

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

    int N, K, C;
    cin >> N >> K >> C;
    vector<ll> B(N);
    for(int i = 0; i < N; i++) cin >> B[i];
    ll L, R;
    cin >> L >> R;

    // 1) Precompute prefix sums P[d][i] = sum_{m=0..i-1} m^d * B[m], stored as __int128
    vector<vector<__int128>> P(C+1, vector<__int128>(N+1, 0));
    for(int i = 0; i < N; i++){
        __int128 pow_m = 1;
        for(int d = 0; d <= C; d++){
            P[d][i+1] = P[d][i] + pow_m * B[i];
            pow_m *= i;
        }
    }

    // 2) build binomial coefficients comb[c][d]
    vector<vector<ll>> comb(C+1, vector<ll>(C+1,0));
    for(int n=0; n<=C; n++){
      comb[n][0] = comb[n][n] = 1;
      for(int k=1; k<n; k++)
        comb[n][k] = comb[n-1][k-1] + comb[n-1][k];
    }

    // 3) for each start j, binary‑search the minimal and maximal end i so that
    //    S(j,i) = sum_{t=0..i-j-1} t^C * B[j+t]  lies in [L..R].
    //
    //    Using the binomial shift:
    //      S(j,i) = sum_{m=j..i-1} (m-j)^C * B[m]
    //             = sum_{d=0..C}  comb[C][d] * (-j)^(C-d) *
    //                            ( P[d][i] - P[d][j] )
    //
    vector<int> lo(N), hi(N);
    for(int j = 0; j < N; j++){
      // precompute (-j)^e for e=0..C
      vector<__int128> negpow(C+1,1);
      for(int e = 1; e <= C; e++)
        negpow[e] = negpow[e-1] * -(__int128)j;

      // lambda to compute S(j,i):
      auto segval = [&](int i){
        __int128 v = 0;
        for(int d = 0; d <= C; d++){
          __int128 diff = P[d][i] - P[d][j];
          v += (__int128)comb[C][d] * negpow[C-d] * diff;
        }
        return v;
      };

      // find lo[j] = smallest i in [j+1..N] with segval(j,i) >= L
      int a = j+1, b = N, ans_lo = N+1;
      while(a <= b){
        int mid = (a+b)>>1;
        if(segval(mid) >= (__int128)L){
          ans_lo = mid; 
          b = mid-1;
        } else a = mid+1;
      }
      lo[j] = ans_lo;

      // find hi[j] = largest i in [j..N] with segval(j,i) <= R
      // i=j yields empty segment => S=0; but we enforce i>j so start at j+1
      a = j+1; b = N; 
      int ans_hi = j;  // no valid if stays j
      while(a <= b){
        int mid = (a+b)>>1;
        if(segval(mid) <= (__int128)R){
          ans_hi = mid;
          a = mid+1;
        } else b = mid-1;
      }
      hi[j] = ans_hi;
    }

    // 4) DP: dp[t][i] = #ways to cut first i bars into t segments,
    //    we'll only keep two rows and do range‑updates via a difference array.
    vector<ll> prev(N+1,0), curr(N+1,0);
    prev[0] = 1;  // zero bars, zero segments → 1 way

    for(int t = 1; t <= K; t++){
      // diff array of size N+2 to do range add on [lo[j]..hi[j]] of prev[j]
      vector<ll> diff(N+2,0);
      for(int j = 0; j < N; j++){
        if(prev[j]==0) continue;
        int l = lo[j], r = hi[j];
        if(l <= r && l <= N){
          diff[l] = (diff[l] + prev[j]) % MOD;
          diff[r+1] = (diff[r+1] - prev[j] + MOD) % MOD;
        }
      }
      // prefix‑sum diff → curr
      ll run = 0;
      for(int i = 0; i <= N; i++){
        run = (run + diff[i]) % MOD;
        curr[i] = run;
      }
      swap(prev, curr);
      fill(curr.begin(), curr.end(), 0);
    }

    // answer = prev[N] (exactly K segments, using all N bars)
    cout << prev[N] << "\n";
    return 0;
}