2021 CCPC (Harbin)--I. Power and Zero

Given a sequence A1, A2, · · · , An whose elements are all positive integers. You should do some operations to make the sequence all zero. For each operation, you can appoint a sequence B1, B2, · · · , Bm (Bi ∈ {1, 2, · · · , n}) of arbitrary length m and reduce ABi by 2 i−1 respectively. Specially, one element in the given sequence can be reduced multiple times in one operation. Determine the minimum possible number of operations to make the given sequence all zero. Input The first line contains one integer T (1 ≤ T ≤ 1000), denoting the number of test cases. For each test case: The first line contains one integer n (1 ≤ n ≤ 105 ), denoting the length of given sequence. The second line contains n integers A1, A2, · · · , An (1 ≤ Ai ≤ 109 ), denoting the given sequence. It is guaranteed that Pn ≤ 105 . Output For each test case: Output one line containing one integer, denoting the answer

input

3
5
1 2 3 4 5
2
1 4
1
7

output

3
3
1

题意:经过N次操作后,所有数都变为0,单次操作方式为进行选择某个数减去2的幂次(若干次),但每减一次,2的幂次+1,幂次从0开始,(就是减1,2,4,8,16....)问最小操作次数。 

解析:我们可以把所有数转为2进制,问题就转化为,把所有出现的1消去,需要操作多少次。我们可以贪心,尽可能一次删去多个1。一次操作中,从1位置开始,每个位置最多删除一个1,倘若某个位置不存在1,我们就得把后面的1减了,然后会在某些位置补上1,如此反复,直到所有1都删完,输出cnt。

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int a[35],maxn;//记录二进制下第i个位置1的个数,maxn记录1出现的最远位置
void add_iner(int n)//统计n二进制对应位置1的个数
{
	int x=0;
	while(n) a[++x]+=n%2,n/=2;
	maxn=max(maxn,x);//更新最大位置
}
void solve()
{
	memset(a,0,sizeof a);//多组初始化
	int n,l,cnt=0;
	maxn=0;
	scanf("%d",&n);
	while(n--) scanf("%d",&l),add_iner(l);
	while(1)
	{
		int f=0;//记录当前操作是否删1,如果没有删过,那么其实代表已经全部为0
		for(int i=1;i<=maxn;i++)
		{
			if(a[i]) a[i]--,f=1;//当前位置有1,减了即可
			else{//当前位置不存在1,作用在后面的1
				for(int j=i+1;j<=maxn;j++)//寻找后面的1
				{
					if(a[j])
					{
						a[j]--;
						f=1;
						int v=(int)pow(2,j-1);//该位置的值
						int k=(int)pow(2,i-1);//可以减少的数
						add_iner(v-k);//当前位置减了,会在某些位置出现1
						break;
					}
				}
			}
		}
		if(!f) break;//已经全部归0
		cnt++;
		while(a[maxn]==0) maxn--;//更新最大位置
	}
	printf("%d\n",cnt);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--) solve();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值