Codeforces 1254B1 - Send Boxes to Alice (Easy Version)


題意

\(n(1\leq n\leq 10^5)\)個盒子,每個盒子有\(a_i(0\leq a_i \leq 1)\)個糖果,你每一次可以將第\(i\)個盒子里的糖果放到第\(i-1\)\(i+1\)個盒子中(如果盒子存在)。最后要使每個盒子的糖果數量都整除\(k(k>1)\)(注意盒子可以為空),問最小操作數。

分析

\((1)\)因為糖果是類似於平鋪的形式,堆疊時,我們可以發現所有存在糖果的盒子中數量均為\(k\)。若存在一個盒子中有\(2*k\)個糖果,在平鋪到堆疊的過程中,將另外\(k\)個糖果分在更近的盒子能得到更小的答案。

\((2)\)設糖果總數為\(cnt\),所有存在糖果的盒子數量均為\(k\),我們又可以發現,最小的操作是將\(1\)~\(k\)\(k+1\)~\(2k\)、……、\(i*k+1\)~\((i+1)*k\)放在一起,即將相鄰的\(k\)個放在一堆。

\((3)\)對於某\(k\)個糖果,需要找到一個盒子,這個盒子到這\(k\)個糖果的距離最小(kNN算法)。我們將糖果看成數軸上的點,運用高一的絕對值知識(我忘了,我向高中數學老師謝罪)。

  • \(k\)為奇數,則將該盒子設置為最中間糖果所在的盒子
  • \(k\)為偶數,則將該盒子設置為最中間兩個糖果中任意一個所在的盒子

即對於\(i*k+1\)~\((i+1)*k\)來說,第\(k-i/2\)個盒子,設其坐標為\(ave\)

\((4)\)為降低時間復雜度,我們采取前綴的思想,\(sum[i]\)表示坐標\(i\)之前的糖果的坐標總和(沒糖果的盒子不加),\(num[i]\)表示坐標\(i\)之前有多少糖果。

\((5)\)枚舉可以被\(cnt\)整除的\(k\),模擬\((2)\)的過程,設\(first\)為第\(i*k+1\)個糖果的坐標,\(last\)為第\((i+1)*k\)個糖果的坐標,那么每個循環都得加上\((num[ave] - num[first - 1])*ave-(sum[ave] - sum[first - 1])+(sum[last] - sum[ave])-(num[last] - num[ave])*ave\),意思為\(ave\)之前的操作次數加上\(ave\)之后的操作次數,最后取最小值

\((6)\)記得開\(long\ long\)\(INF\)也記得開大一點。

#pragma GCC optimize(3, "Ofast", "inline")

#include <bits/stdc++.h>

#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define LL long long
#define pii pair<int,int>
#define int ll
using namespace std;
const int maxn = (ll) 1e5 + 5;
const int mod = 1000000007;
const int inf = 0x3f3f3f3f3f3f3f3f;
int a[maxn];
int cnt = 0;
int sum[maxn];
int num[maxn];

signed main() {
    start;
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        num[i] = num[i - 1] + x;//前綴數量
        if (x) {
            a[++cnt] = i;
            sum[i] = i;
        }
    }
    for (int i = 1; i <= n; ++i)//前綴坐標和
        sum[i] += sum[i - 1];
    int ans = inf;
    for (int i = 2; i <= cnt; ++i) {
        if (cnt % i == 0) {
            int tmp = 0;
            for (int k = i; k <= cnt; k += i) {//k為最后的糖果
                int first = a[k - i + 1];
                int last = a[k];
                int ave = a[k - i / 2];
                int num1 = num[ave] - num[first - 1];
                int num2 = num[last] - num[ave];
                int tot1 = sum[ave] - sum[first - 1];
                int tot2 = sum[last] - sum[ave];
                int t = num1 * ave - tot1 + tot2 - num2 * ave;
                tmp += t;
            }
            ans = min(ans, tmp);
        }
    }
    if (ans == inf)
        cout << -1;
    else
        cout << ans;
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM