Submission

Status:

PPPPPPPPPPPPPPPP

Subtask/Task Score:

160/160

Score: 160

User: syndrxme

Problemset: Chocolate

Language: cpp

Time: 0.077 second

Submitted On: 2026-03-14 14:40:33

#include <iostream>
#include <vector>

using namespace std;

const int MOD = 1000000007;

int main() {
    // โหมด Fast I/O เพิ่มความเร็ว
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int n, k_parts, c;
    if (!(cin >> n >> k_parts >> c)) return 0;

    vector<long long> A(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> A[i];
    }

    long long L, H;
    cin >> L >> H;

    // 1. คำนวณเลขยกกำลังล่วงหน้า (Precompute Powers)
    // ระวังเงื่อนไข 0^0 = 1 
    vector<long long> P(n + 1, 0);
    P[0] = (c == 0) ? 1 : 0; 
    for (int i = 1; i <= n; i++) {
        long long p = 1;
        for (int j = 0; j < c; j++) {
            p *= i;
            if (p > H) { p = H + 1; break; } // กันตัวเลขล้น (Overflow)
        }
        P[i] = p;
    }

    // 2. หาช่วงรอยตัดที่ถูกต้อง [left_j, right_j] สำหรับแต่ละจุดสิ้นสุด i
    vector<int> left_j(n + 1, n + 1);
    vector<int> right_j(n + 1, -1);

    for (int j = 0; j < n; j++) { // j คือจุดที่ถูกตัดก่อนหน้า (รอยต่อ)
        long long cost = 0;
        for (int i = j + 1; i <= n; i++) { // i คือช่องที่เรากำลังจะพิจารณา
            long long power = P[i - j - 1];
            if (power > H) break; // ถ้าแค่ตัวคูณก็เกิน H แล้ว ให้ข้ามเลย
            
            long long term = power * A[i];
            if (term > H || cost + term > H) break; // ถ้ารวมแล้วเกิน H ก็ไม่ต้องลาก i ต่อแล้ว
            
            cost += term;

            if (cost >= L) { // ถ้ามูลค่าอยู่ในช่วง [L, H] จดรอยตัด j เอาไว้
                left_j[i] = min(left_j[i], j);
                right_j[i] = max(right_j[i], j);
            }
        }
    }

    // 3. เริ่มทำ Dynamic Programming
    vector<long long> dp(n + 1, 0);
    dp[0] = 1; // Base case: ช็อกโกแลต 0 ชิ้น แบ่งเป็น 0 ส่วน ได้ 1 วิธี

    for (int k = 1; k <= k_parts; k++) { // ลูปแบ่งทีละรอบ จนครบ k_parts ส่วน
        vector<long long> next_dp(n + 1, 0);
        vector<long long> pref(n + 1, 0); // Prefix Sum ของ DP รอบที่แล้ว
        
        pref[0] = dp[0];
        for (int i = 1; i <= n; i++) {
            pref[i] = (pref[i - 1] + dp[i]) % MOD;
        }

        for (int i = 1; i <= n; i++) {
            // ถ้ารอยตัดซ้าย-ขวาถูกต้อง (มีคำตอบ)
            if (left_j[i] <= right_j[i]) {
                long long sum = pref[right_j[i]];
                if (left_j[i] > 0) {
                    // การลบด้วย Modulo ต้องระวังค่าติดลบ จึงต้อง + MOD เข้าไปก่อน
                    sum = (sum - pref[left_j[i] - 1] + MOD) % MOD;
                }
                next_dp[i] = sum;
            }
        }
        dp = next_dp; // อัปเดตคำตอบเพื่อใช้ในรอบถัดไป
    }

    // พิมพ์คำตอบของช่องสุดท้าย (n) หลังแบ่งครบ K ส่วน
    cout << dp[n] << "\n";

    return 0;
}