codeforces 1940B

题意:

多测,每一次给出一个n。一开始有n个0,每次可以选择以下两个操作执行任意次:

1.给其中一个位置i,让ai项变成1。

2.给出lr,使1\leq l\leq r\leq n,若al和ar都是一,且lr的和\geq \frac{r-l+2}{2}。那么让lr的所有数都变成1。

问:是所有数都变成一最少要执行多少个1类型?

样例:

4
1
2
4
20
1
2
2
4

 

思路:

我么不难能够想到,可以把n分成许多块,每一块都放一半的1,假设分了k块,每一块的长度是s1,s2,s3......sk-1,sk,sk指的是第k块的长度。那么发现,每个块互相是不影响的。所以需要再改进。

我们来看一下下面这个例子

n=22

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

我们在第一个和第四个上面放1,在第十个上面放1,在最后一个上面放1,

1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1

然后对

1到4执行而操作2

1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1

这个操作使原来不可以执行2类型操作的1到10变得可以执行二类型操作。

1到10执行操作2

1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1

这个操作又使这个区间可以变成一

那么做法便推导出来,一开始在头部放一个1。

然和重复执行以下操作直到成为一的数量等于甚至大于n:

1.假设放了a个连续一(这种方法的一是连续的,且从第一个位置开始连续),在(a+1)*2位置放一个1,然后对1~(a+1)*2执行二类型操作(下面解释为什么可以执行二操作),现在就有2*(a+1)个一。然和更新a为2*(a+1),那么下一次操作的a就是这次的(a+1)*2了。

解释:1~(a+1)*2的长度是2*(a+1),原先放了a个一,现在有a+1个,正好有一半。

代码如下(不要无脑复制):

#include <bits/stdc++.h>
#define int long long//坏习惯改不掉了
#define rep(i,a,b) for(int i=a;i<b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

void solve(){
	int n,cnt=1,sum=1;//分别是执行一操作的数量和总1的数量
	cin>>n;
	while(n>sum){
		cnt++;//放1
		sum=2*(sum+1);//更新1的数量
	}
	cout<<cnt<<"\n";
}
signed main(){
	int T=1;
	cin>>T;
	while(T--)solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值