P1031均分纸牌 - - (https://www.luogu.com.cn/problem/P1031)
Sample Input
4
9 8 17 6
Sample Output
3
分析:
一开始想得挺复杂的,想找到一个最大值(动态的)然后分给旁边的,然后找到接下来的最大值在继续分下去、、、错的挺离谱。后面就想到了平均值这个东西。
先求出这n堆牌的平均值,然后再让每一堆牌减去这个平均值为剩余牌(j>0)/缺少牌(j<0)的数量,用变量j记录。如果j是正数,把当前堆的剩余牌移到下一堆牌上;如果j是负数,就从下一堆牌里拿j张直到当前堆的牌数量达到平均值;如果j是0,就不用动.....以此类推,每移动一次(j不为0的时候)移动次数count+1,由于是平均值,所以最晚执行完倒数第二堆牌的时候每个牌堆里的牌数量就已经是相等的了。
一开始还考虑了j大于0或者j小于0的情况,处理当前堆:为负数的时候加j的绝对值,为正数的时候直接减j;处理下一堆:负数的时候减去j的绝对值;正数的时候直接加上j。
后面找出规律:不管正负,当前堆的处理都是-j,下一堆都是+j,简化了代码核心。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int main(){
int n,sum=0,aver,count=0;
cin>>n;
int a[n];
for(int i=0;i<n;i++){
cin>>a[i];
sum+=a[i];
}
aver=sum/n;
for(int i=0,j;i<n-1;i++){
j=a[i]-aver;
if(j!=0){
a[i]-=j;
a[i+1]+=j;
count++;
}
}
cout<<count<<endl;
}
P6364 1024 程序员节发橙子(https://www.luogu.com.cn/problem/P6364)
Sample Input
5
3 4 5 4 3
10
1 2 3 4 1 2 3 2 3 4
4
1 4 3 2
5
1 2 3 2 3
5
3 4 5 5 1
Sample Output
9
22
7
9
10
ps:因为题目给的测试用例太少太普遍,思考不全面导致一些bug出现,自己加了几个算是比较奇怪的测试用例
思路:
吃了测试用例少的亏,我换了三次思路。
第一次是想着直接求出最小值min和max,min随着循环进行一层层叠加,当有数字大于等于min的时候sum++,直到min>max,停止。想得太理所当然了完全没有想到如果 1 2 3 2 3这种情况,得出的结果是13而不是9;
第二次思路受益于前两天做的模拟题“均分纸牌”,因为那里也出现了相邻的思想,于是就想着把目光放在了单独的数字上,于是就有了一个存放数字的数组a,一个存放橙子个数的数组count,从左到右从右到左(像类似1 4 3 2这组数据光从一边遍历的count数组里数据是 1 2 1 1显然是不对的!)控制数组count达到“分数相同橙子个数一样,分数高橙子多”的要求,局限性地把数组a的最大值max求出来控制拐点,完全没有考虑到可能会有多个值不同的拐点(极大值),如:1 2 3 4 1 2 3 2 3 4,这里就有两个极大值:4 3;
所以在第三次修改我的思路的时候,我直接把有关max值的代码全部去掉了,还是利用回count数组的值控制从右到左遍历的时候橙子的个数需不需要改,很显然修改后的个数必须大于等于原来的个数,才能允许修改,比如
3 4 5 5 1,分到的橙子应该分别是1 2 3 3 1,一共是10个;而如果缺少这个判断则会变成 1 2 3 2 1, 是9个,很明显不符合题目要求。
代码如下:
#include<iostream>
using namespace std;
int main(){
int n,min,max;
while(cin>>n){
unsigned long long int sum=0;
int a[n],count[n];
for(int i=0;i<n;i++){
cin>>a[i];
count[i]=1;
}
for(int i=1;i<n;i++){//从左到右
if(a[i]>a[i-1]){
count[i]=count[i-1]+1;
}
else if(a[i]==a[i-1]){//分数相等橙子数必须一样
count[i]=count[i-1];
}
}
for(int i=n-2;i>=0;i--){//从右到左
if(a[i]>a[i+1]&&count[i+1]+1>=count[i]){//第二次遍历的count不能第一次的小
count[i]=count[i+1]+1;
}
else if(a[i]==a[i+1]){
count[i]=count[i+1];
}
}
for(int i=0;i<n;i++)sum+=count[i];
cout<<sum<<endl;
}
}