1. 程式人生 > >Luogu 1031 - 均分紙牌 - [有意思的思維題]

Luogu 1031 - 均分紙牌 - [有意思的思維題]

題目連結:https://www.luogu.org/problemnew/show/P1031

題目描述
有 $N$ 堆紙牌,編號分別為 $1,2,…,N$。每堆上有若干張,但紙牌總數必為 $N$ 的倍數。可以在任一堆上取若干張紙牌,然後移動。

移牌規則為:在編號為 $1$ 堆上取的紙牌,只能移到編號為 $2$ 的堆上;在編號為 $N$ 的堆上取的紙牌,只能移到編號為 $N-1$ 的堆上;其他堆上取的紙牌,可以移到相鄰左邊或右邊的堆上。

現在要求找出一種移動方法,用最少的移動次數使每堆上紙牌數都一樣多。

例如 $N=4$,$4$堆紙牌數分別為:

①$9$ ②$8$ ③$17$ ④$6$
移動 $3$ 次可達到目的:

從 ③ 取 $4$ 張牌放到 ④ $(9,8,13,10)$ -> 從 ③ 取 $3$ 張牌放到 ② $(9,11,10,10)$ -> 從 ② 取 $1$ 張牌放到① $(10,10,10,10)$。

輸入輸出格式
輸入格式:
兩行

第一行為:$N$($N$ 堆紙牌,$1 \le N \le 100$)

第二行為:$A_1,A_2, … ,A_n$($N$堆紙牌,每堆紙牌初始數,$1 \le A_i \le 10000$)

輸出格式:
一行:即所有堆均達到相等時的最少移動次數。

輸入輸出樣例
輸入樣例#1:
4
9 8 17 6
輸出樣例#1:
3

 

題解:

首先,由於總牌數是 $N$ 的整數倍,因此肯定是可以有解的。每個牌堆最終的牌數就是總牌數除以堆數,設為 $k$。

其次,任意相鄰的兩個牌堆之間,最多隻進行一次移牌操作,否則就是多餘操作(這是很顯然的)。因此,不管怎麼樣,移動次數最多也就 $N-1$ 次。

那麼,如何判斷這個間隔是否需要進行移牌操作?

其實很簡單,假設這個間隔是牌堆 $i$ 和 牌堆 $i+1$ 的間隔,那麼只要前 $i$ 堆牌數之和不等於 $k \cdot i$,就要在牌堆 $i$ 和牌堆 $i+1$ 之間進行一次移牌操作。

原因也很簡單,左邊的牌數不對,右邊的牌數自然也不對,如果不在當前這個間隔移牌,就不可能讓左右兩邊的牌數變對,因此必須移牌。

 

AC程式碼:

#include<bits/stdc++.h>
using
namespace std; int n,k,s[105]; int main() { cin>>n; for(int i=1,x;i<=n;i++) cin>>x, s[i]=s[i-1]+x; k=s[n]/n; int ans=0; for(int i=1;i<=n;i++) if(s[i]!=k*i) ans++; cout<<ans<<endl; }