csdn编程练习之-3+1

来源:互联网 发布:热血传奇数据库 编辑:程序博客网 时间:2024/04/30 02:20

题目详情:

有一个数列,所有的数都是非负整数,你可以进行如下方式进行一次操作(注意一次完整的操作必须先后完成如下两个步骤):

(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;}


0 0
原创粉丝点击