Kitchen Timer——二进制+前缀和

肯尼的厨房里有一台微波炉。微波炉有一个非常奇怪的一键定时器接口。
当你把一些食物放进微波炉并想让它开始加热时,你应该按下按钮一次或多次。当您第一次按下按钮时,计时器设置为1分钟。如果立即再次按下按钮,则计时器将增加2分钟,总共3分钟。如果你立即再次按下按钮,计时器将增加4分钟,依此类推。如果你第k次不停顿地按下按钮,则计时器将增加2k分钟。
使用按钮似乎不可能在某些时间段内设置计时器:例如,如何将计时器设置为2分钟?幸运的是,您可以通过暂停一秒钟来重置按钮计数器。因此,例如,如果你按下按钮,暂停一秒钟,然后再次按下按钮,计时器将设置为2分钟。另一个例子:如果按、按、暂停、按、按,计时器上的总时间为1+2+1+2+4=10分钟。
肯尼需要把食物加热整整x分钟。帮助他找到设置计时器所需的最小1秒暂停次数。让我们假设只有暂停需要时间,而按下按钮的时间被忽略。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量t(1≤t≤1e4)。测试用例的描述如下。
每个测试用例的唯一一行包含一个整数x,表示Kenny需要加热食物的分钟数(1≤x≤1e18)。
输出
对于每个测试用例,打印一个整数,表示Kenny在将微波计时器设置为x分钟时需要暂停的最小1秒数。

样例输入:
7
1
2
3
4
10
239
123456789012
样例输出:
0
1
0
1
1
4
19

注意:
在第一个示例测试用例中,不需要停顿:Kenny只需按下一次按钮。
在第二个示例测试用例中,Kenny可以按下、暂停、按下以将计时器设置为2分钟。
在第三个示例测试用例中,Kenny只需按下两次按钮即可将计时器设置为3分钟。
在第四个示例测试用例中,Kenny可以按、按、暂停、按以将计时器设置为1+2+1=4分钟。

#include 
using namespace std;
#define int unsigned long long //要有足够的范围,要不然爆表,存不下2e65-1
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef pair PII;
const int N=2e6+10;
int a[N],n;
int qmi(int a,int k)
{
	int ans=1;
	while (k)
	{
		if (k&1) ans=ans*a;
		k >>=1;
		a=a*a;
	}
	return ans;
}
void find()   //预处理
{
	for (int i=65;i>=1;i--)
	{
		a[i-1]=qmi(2,i)-1;
	}
}
signed main()
{
	ios;
	find();
	int t;
	cin>>t;
	while (t--)
	{
		cin>>n;
		int ans=0;
		for (int i=64;i>=0;i--)
		{
			ans +=n/a[i];
			n %=a[i];
			if (n==0) break;  //在 unsigned long long 范围,此处不可省!!
		}
		ans--;    
		cout<

你可能感兴趣的:(数据结构,算法)