คำอธิบายวิธีทำพร้อม code สำหรับข้อ toi20_lover

สรุปโจทย์

มี NN ร้าน(NN เป็นเลขคู่) โดยร้านที่ ii มีราคา xix_i

โดยต้องแบ่งช่วงการกินข้าวเป็นช่วงๆ สมมติว่ามี MM ช่วง โดยต้องให้ l1+l2++lM=Nl_1+l_2+\cdots+l_M=N และ ljl_j คือจำนวนร้านที่กินในช่วงการกินข้างที่ jj และ ljl_j ต้องเป็นเลขคู่

โดยช่วงการกินที่ 11 จะเริ่มกินจากร้านที่ 11 ไปจนถึงร้านที่ l1l_1
ช่วงการกินที่ 22 จะเริ่มกินจากร้านที่ l1+1l_1+1 ไปจนถึงร้านที่ l1+l2l_1+l_2
ช่วงการกินที่ jj จะเริ่มกินจากร้านที่ l1+l2++lj1+1l_1+l_2+\cdots+l_{j-1}+1 ไปจนถึงร้านที่ l1+l2++ljl_1+l_2+\cdots+l_j

สมมติให้ช่วงการกินที่ jj กินจากร้านที่ pp ไปร้านที่ qq โดยช่วงการกินจะแบ่งเป็น 22 รอบ รอบแรกจะกินร้านที่ pp จนถึงร้านที่ p+q12\frac{p+q-1}{2} และกินเฉพาะร้านที่มีราคาเป็นเลขคี่ รอบที่สองจะกินจากร้านที่ p+q12+1\frac{p+q-1}{2}+1 จนถึงร้านที่ qq และกินเฉพาะร้านที่มีราคาเป็นเลขคู่

ให้ผลรวมราคาที่กินไปของรอบแรกของช่วงที่ jj เป็น aja_j และให้ผลรวมราคาของรอบที่สองที่กินไปของช่วงที่ jj เป็น bjb_j เราต้องให้ max(a1,a2,,aM)V\max(a_1,a_2,\cdots,a_M)\leq V และ max(b1,b2,,bM)W\max(b_1,b_2,\cdots,b_M)\leq W

ให้หาว่า MM มีค่าน้อยสุดคือเท่าไหร่

Prerequisites

ขอบเขตข้อมูล

วิธีทำ

สังเกตได้ว่าการที่ max(c1,c2,,cK)D\max(c_1,c_2,\cdots,c_K)\leq D แปลว่า cjDc_j \leq D สำหรับทุกๆ 1jK1\leq j\leq K

จะได้ว่าถ้าให้ dp[n]=dp[n]= ค่า MM ที่น้อยที่สุดโดยที่คิดแค่ nn ร้านแรก และช่วงการกินช่วงสุดท้ายจบที่ร้านที่ nn สังเกตได้ว่า dp[n]=maxi<n, ni  0(mod2)โดยที่ผลรวมราคาที่กินไปของรอบแรกVโดยที่ผลรวมราคาที่กินไปของรอบที่สองWdp[i]+1\displaystyle dp[n]=\max_{\substack{i<n,\space n-i \space \equiv \space 0 \pmod 2\\ \text{โดยที่ผลรวมราคาที่กินไปของรอบแรก}\leq V\\ \text{โดยที่ผลรวมราคาที่กินไปของรอบที่สอง}\leq W}}dp[i]+1

ถ้าเราให้ podd[j]=p_{odd}[j]= ผลรวมของทุกๆ ราคาเมื่อราคาเป็นเลขคี่เมื่อคิดแค่ jj ร้านแรก และ peven[j]=p_{even}[j]= ผลรวมของทุกๆ ราคาเมื่อราคาเป็นเลขคู่เมื่อคิดแค่ jj ร้านแรก

เราจะให้ mid=n+i2mid=\frac{n+i}{2}

เราจะพิจารณาผลรวมราคาที่กินไปของรอบแรกก่อน นั่นก็คือ podd[mid]podd[i]Vp_{odd}[mid]-p_{odd}[i]\leq V
จากนั้นเราจะพิจารณาผลรวมราคาที่กินไปของรอบที่สอง นั่นก็คือ peven[n]peven[mid]Wp_{even}[n]-p_{even}[mid]\leq W

ซึ่งทั้งคู่สามารถเช็คได้ใน O(1)O(1) เนื่องจากเราต้องเช็คทุกๆ i<ni<n ที่ ni  0(mod2)n-i \space \equiv \space 0 \pmod 2 สำหรับ dp[n]dp[n] ซึ่งต้องเช็ค O(N)O(N) จุด แล้วเราต้องทำ dp[n]dp[n] สำหรับทุกๆ n<Nn<N จะได้ว่าเวลารวมที่จำเป็นต้องใช้คือ O(N2)O(N^2)

Solution Code:

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

const int inf = 1e9;

int main(){
    cin.tie(NULL)->sync_with_stdio(false);
    int n, v, w; cin >> n >> v >> w;
    vector<int> a(n + 1), p_odd(n + 1), p_even(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        p_odd[i] = p_odd[i - 1];
        p_even[i] = p_even[i - 1];
        if (a[i] % 2) p_odd[i] += a[i];
        else p_even[i] += a[i];
    }
    vector<int> dp(n + 1, inf); dp[0] = 0;
    for (int r = 2; r <= n; r+=2) {
        for (int l = r-2; l >= 0; l-=2) {
            int mid = (l+r)/2;
            int vs = p_odd[mid] - p_odd[l],
	            ws = p_even[r] - p_even[mid];
            if (vs <= v && ws <= w) dp[r] = min(dp[r], dp[l] + 1);
        }
    }
    cout << (dp[n] == inf ? -1 : dp[n]);
}

Time Complexity: O(N2)O(N^2)

หากมีข้อสงสัย comment ไว้ใต้ post ได้เลยนะครับ 🙇‍♂️🙇‍♂️
ศึกษาโจทย์เพิ่มเติมได้ที่ Fast X Fourier