Codeforces Round #774 (Div. 2) C. Factorials and Powers of Two

题目链接
在这里插入图片描述
比赛的时候第一反应是一个背包dp,但很显然直接dp的话会寄掉。
比赛完了以后仔细想了想,发现这个题就是递归式的递推(自己起的名字)
我们定义 d f s ( i , s u m ) dfs(i,sum) dfs(i,sum)为下标为 0 − i 0-i 0i的数中,总和为 s u m sum sum的数的最小个数,则状态转移为:
d f s ( i , s u m ) = m i n ( d f s ( k − 1 , s u m − a r r [ k ] ) + 1 ) dfs(i,sum)=min(dfs(k-1,sum-arr[k])+1) dfs(i,sum)=min(dfs(k1,sumarr[k])+1),其中 k k k的上界通过右边界二分确定,下界通过前缀和确定。若不存在,则设为 i n f inf inf

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
 
using namespace std;
typedef long long ll;
 
const ll N = 1e12 + 10;
const int inf = 0x3f3f3f3f;
int t, cnt;
ll n;
 
vector<ll>arr;
ll pre[60];
 
void m_init()
{
	ll i , j;
 
	i = 0;
	while (1)
	{
		j = pow(2, i);
		if (j <= N)
			arr.push_back(j);
		else
			break;
		++i;
	}
 
	i = 1, j = 1;
	while (1)
	{
		i *= j;
 
		if (i <= N)
			arr.push_back(i);
		else
			break;
		++j;
	}
 
	sort(arr.begin(), arr.end());
	arr.erase(unique(arr.begin(), arr.end()), arr.end());
	cnt = arr.size();
 
	pre[0] = arr[0];
	for (i = 1; i < cnt; ++i)
		pre[i] = pre[i - 1] + arr[i];
}
 
int dfs(int i, ll sum)  		//0-i的数,总和为sum的最小数量 
{
	if (sum == 0)
		return 0;
 
	int left = 0, right = i, mid, j, k,res = inf;
 
	while (left <= right)
	{
		mid = (left + right) >> 1;
 
		if (arr[mid] <= sum)
			left = mid + 1;
		else
			right = mid - 1;
	}
 
	for (j = right; j>=0&&j<=cnt-1&&pre[j] >= sum; --j)
		res = min(res, dfs(j - 1, sum - arr[j]) + 1);
	
	return res;
}
 
int main()
{
	m_init();
 
	int ans;
 
	scanf("%d", &t);
	while (t--)
	{
		scanf("%lld", &n);
 
		ans = dfs(cnt-1, n);
 
		if (ans == inf)
			printf("%d\n", -1);
		else
			printf("%d\n", ans);
	}
 
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值