1. 程式人生 > 其它 >七夕祭:分治+貪心+排序+字首和+中位數

七夕祭:分治+貪心+排序+字首和+中位數

技術標籤:2021寒假藍橋杯刷題

我們先來看一道簡化版的

均分紙牌:

異曲同工之處,均分紙牌是一維的,並且空間是正常的。

首先判斷可不可以均分紙牌,如果可以,為了使得第一堆紙牌可以均分,必須後面一堆紙牌拿牌層層遞推。

#include <iostream>

using namespace std;
int n, sum, ans;
int a[110];
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sum +
= a[i]; } int avg = sum / n; for(int i = 1; i < n; i++) { if(a[i] != avg) a[i + 1] -= avg - a[i], ans++; } //cout << avg << endl; cout << ans << endl; return 0; }

七夕祭:

首先,橫向或者豎向移動不會改變另一個方向的紙牌我們只需要單獨考慮行和列
這個空間扭曲了,因此不是簡單的移動了,需要選擇中位數作為參考的標誌點。

我們假設空間沒有扭曲的情況下,答案應該是字首和陣列的字首和。
通過扭曲空間,需要找一箇中心的位置,使得移動的次數最少,變成了倉庫選址問題

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
#define ll long long
ll n, m, ans;
ll t;
ll x[N], y[N], f[N];
ll int calc(ll int a[N],int k)
{
    ll avg = a[
0] / k; ll res = 0; for(int i = 1; i <= k; i++) { a[i] -= avg; f[i] = f[i - 1] + a[i]; } sort(f + 1, f + k + 1); for(int i = 1; i <= k; i++) { res += abs(f[i] - f[k + 1 >> 1]); } return res; } int main() { cin >> n >> m >> t; for(int i = 1; i <= t; i++) { int a, b; cin >> a >> b; x[a]++; y[b]++; x[0]++; y[0]++; } if(x[0] % n == 0 && y[0] % m == 0) { ans = calc(x, n) + calc(y, m); cout << "both " << ans << endl; } else if(x[0] % n == 0) { ans = calc(x, n); cout << "row " << ans << endl; } else if(y[0] % m == 0) { ans = calc(y, m); cout << "column " << ans << endl; } else cout << "impossible" << endl; return 0; }