1. 程式人生 > 其它 >「巧克力」題解

「巧克力」題解

因為不開 long long 難了我好久的「巧克力」……我太蒻了。

「巧克力」題解

題目

學校的網站,一般人上不去。題目連結:Link

有一塊高 \(H\) 塊,寬 \(W\) 塊的巧克力, 小明將其分為 \(3\) 塊。他只能沿著每塊巧克力的邊緣切割,並且切割的形狀必須是一個長方形。 小明希望儘可能的平均切割,也就是他希望 \(S_{max} – S_{min}\) 儘可能的小, \(S_{max}\) 是最大那一份的面積 (包含的塊數), \(S_{min}\) 是最小那一份的面積。 求 \(S_{max} – S_{min}\) 的最小值。

程式碼

如果光看樣例,會簡單地以為答案是 \((H \bmod 3) \times (W \bmod 3)\),其實不然。這道題本質上就是一個列舉優化的程式碼。列舉一刀切的位置(這裡可以再優化,只在 \(\frac{1}{3}H \pm 5\)

的位置列舉就可以),再在剩下的區域中儘量平均分——容易證明這樣是最優的。

當然了,最開始列舉的那刀可以橫切頁可以豎切,所以這樣完之後 swap(H,W) 一下就可以了。

資料範圍到了 \(10^5\)——十年 OI 一場空,不開 long long 見祖宗!程式碼如下:

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

ll x, y, ans;

void mov(ll a, ll b) {ans = min(ans, max(max(a, b), x * y - a - b) - min(min(a, b), x * y - a - b));}
// 算三塊中的最大值減去最小值,更新 ans
void movs() {
    for (ll i = 1; i < x; i++) {
        ll z = x - i; mov(i * y, y / 2 * z); mov(i * y, z / 2 * y);
    }
} // 儘量平均分
int main() {
    cin >> x >> y; // 輸入
    ans = x * y; // ans 初始值 xy
    movs(); swap(x, y); movs(); // 簡單操作,記得 swap
    cout << ans << endl; // 輸出嘍
    return 0;
}

\(10\) 個點跑了 \(21\) ms,稍微有點多,不過程式碼實在很短了。壓行程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll x,y,ans;
void mov(ll a,ll b){ans=min(ans,max(max(a,b),x*y-a-b)-min(min(a,b),x*y-a-b));}
void movs(){for(ll i=1;i<x;i++) {ll z=x-i;mov(i*y,y/2*z);mov(i*y,z/2*y);}}
int main(){cin>>x>>y;ans=x*y;movs();swap(x,y);movs();cout<<ans;return 0;}