题目详情:
有一个数列,所有的数都是非负整数,你可以进行如下方式进行一次操作(注意一次完整的操作必须先后完成如下两个步骤):
(1) 任选一个不小于3的数,把它减少3。
(2) 任选一个数把它增加1。
请问,最多能够操作多少次?
输入格式:
多组数据,每组数据第一行是一个正整数n,表示数列中数的个数。(1<=n<=20000)
第二行包含n个空格分隔的非负整数,每个整数不超过1000000。
输出格式:
对每组数据输出一行,表示最多可以进行的操作次数。
输入:
1
10
2
10 11
输出:
4
10
详解:
先试个简单的例子:输入为2
4 5
则可进行的操作如下:(其他操作方式的最多次数也是一样的)
{1,5,2,5},{2,2,2,3},{2,0,3,0},{0,0,1,0}最多共4次操作。可以看出每有一个大于三的数就可以操作一次,除此之外,通过加1之后大于等于三的数也可以进行一次操作。推广到n则可以这样解:
输入的n个数,我们都可以把这n个数分解成n1个1,n2个2,n3个3。则至少可以进行n3次操作,通过加1可进行的操作数为:(这时候问题可以看成是逢三进一的问题,类似于每三个啤酒瓶能换一瓶啤酒,问有n个啤酒瓶最多能换多少瓶酒的问题)。剩下的数为s=(n1+2*n2+n3),接下来是解决逢三进一的问题,设操作数为t。当s=1,或2时,t=0,当s=3或4时,t=1;以此类推,得到这个数列的通项公式为t=s%2? (s-1)/2 : (s-2)/2; 这t次操作是后面的通过加1可得到的操作数,加上原来最少能进行的操作数即为所要求的次数。
再看看 2 4 5 这个例子。
4 和5 可分成 2个3 和1 个1 和1 个2。即n1=1;n2=1;n3=2;s=(1+2*1+2)=5; t=(5-1)/2=2. 则总操作数为n3+t=4;
代码如下:
#include<iostream>
using namespace std;
int main()
{
int i,n;
while(scanf("%d",&n)!=EOF){
__int64 n1=0,n2=0,n3=0,step=0,sum;
for(i=0;i<n;i++){//把这n个数全部分解成n1个1,n2个2,n3个3;
__int64 num;
scanf("%I64d",&num);
n3+=num/3;
if(num%3==2)
n2++;
if(num%3==1)
n1++;
}
sum=n1+2*n2+n3;//这步可理解为所有“可以加的1”,一共有n1+2*n2+n3个1;
step=n3 + sum%2 ? (sum-1)/2 : (sum-2)/2;//初始步数加上增加的步数;
printf("%I64d\n",step);
}
return 0;
}