题解:P1031 [NOIP 2002 提高组] 均分纸牌
题解:P1031 [NOIP 2002 提高组] 均分纸牌
题目传送门
题意
给出
- 当
i 为1 时,可以将a_{i} 中的一部分移动到a_{i+1} ,也就是a_{2} ; - 当
i 为n 时,可以将a_{i} 中的一部分移动到a_{i-1} ; - 当
1 < i < n 时,可以将a_{i} 中的一部分移动到a_{i+1} 或a_{i-1} 。
显然,这里的“移动”就是使得
反过来,
思路
贪心。
首先,由于要求每个数字相等,那么所有数字的总和一定可以被
此时,对于序列中的每一个数
- 如果
a_{i} > num ,则a_{i} 多出来的部分(a_{i} - num )应该被转移到临近的数上; - 如果
a_{i} < num ,则a_{i} 缺少的部分(num - a_{i} )应该由邻近的数转移而来; - 如果
a_{i} = num ,则不需要进行任何操作。
那么,这个“临近的数”,应该是哪一侧的数呢?
让我们回到这个序列上。
对于
这时,对于
以此类推,我们就解决了刚才的问题:对于
所以,对于序列中的每一个数
- 如果
a_{i} > num ,则a_{i+1} = a_{i+1} + a_{i} - num ,a_{i} = num ; - 如果
a_{i} < num ,则a_{i+1} = a_{i+1} - num + a_{i} ,a_{i} = num ; - 如果
a_{i} = num ,则不需要进行任何操作。
对于前两种情况,不难发现,其实它们进行的操作是一样的。
for(ll i=1;i<n;i++){
if(a[i]==num) continue;//相等则不进行操作
a[i+1]+=(a[i]-num);//否则进行移动
a[i]=num;
ans++;//答案增加
}
代码实现
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,ans,a[110],num;
int main(){
cin>>n;
for(ll i=1;i<=n;i++){
cin>>a[i];
num+=a[i];//求序列和
}num/=n;//求平均数
for(ll i=1;i<n;i++){
if(a[i]==num) continue;//相等则不进行操作
a[i+1]+=(a[i]-num);//否则进行移动
a[i]=num;
ans++;//答案增加
}cout<<ans;
return 0;//好习惯
}//完结撒花QAQ