CodeForces - 1373E Sum of Digits(贪心)

题目链接:点击查看

题目大意:设 f( x ) 为 x 的数位之和,给出一个 n 和一个 k ,求 f(x) + f(x + 1) + \dots + f(x + k) = n 的最小 x ,若不存在,输出 -1

题目分析:因为 n 和 k 比较小,所以可以打表,当 k 为 0 的时候,显然是 r + 99...999 是最优的,其中 r = n%9,当 k 为 1 的时候,打表的时间复杂度是 sqrt( 1e16 ) * 8 ,也就是将近 1e9 ,本地可能绷不住,所以可以打到 1e7 左右,然后自己找找规律补齐剩下的几项就好了,剩下的时间复杂度分别就是 \small \sqrt[3]{1e16}\small \sqrt[4]{1e16}之类的了,本地轻轻松松搞定

然后说一下正解,因为 k 最大只有 9 ,比较显然的一点就是,至多会进位一次,因为我们贪心的策略是较低位都放置 9 ,所以个位的进位会涉及到更高位的连续进位,这样我们不妨设我们最后构造出来的数为 r + 99...999 + 8 + 99..999 + x ,我们将需要构造的数分为了五段,因为说过了,为了贪心,所以低位需要尽量放 9 ,我们设 x 左边的第一堆 9 的个数为 num_9,又因为如果涉及进位的话,会导致连续进位,所以我们在 num_9 个 9 之前,放置了一个 8 ,到此停止连续进位,剩下的再按照当 k = 0 时贪心放置就好了

因为最多只有 1e16,换句话说 num_9 最多只有 16 ,而个位的 x 也最多只有 9 种取值,我们可以暴力枚举 x 和 num_9 ,然后计算此时贪心放置得到的最小值,就好了

代码:
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const LL inf=0x3f3f3f3f3f3f3f3f;

const int N=510;

int n,k;

LL cal(int last,int num_9)
{
	int num=n;
	for(int i=0;i<=k;i++)
	{
		if(last+i<=9)
			num-=last+i+9*num_9;
		else
			num-=last+i-9;
	}
	if(num<0||num%(k+1)!=0)//如果剩下的数小于0了或者不足以恰好分为k+1份,则此时无解
		return inf;
	num/=k+1;
	LL ans=0;
	if(num<9)//按照k=0时贪心分配即可
		ans=num;
	else
	{
		num-=8;//别忘了需要放上一个8用来截断连续的9
		ans=num%9;
		for(int i=1;i<=num/9;i++)
			ans=ans*10+9;
		ans=ans*10+8;
	}
	for(int i=1;i<=num_9;i++)
		ans=ans*10+9;
	ans=ans*10+last;
	return ans;
}

LL solve()
{
	LL ans=inf;
	for(int i=0;i<10;i++)//枚举个位的x
		for(int j=0;j<=16;j++)//枚举x前有多少个9:num_9
			ans=min(ans,cal(i,j));
	if(ans==inf)
		ans=-1;
	return ans;
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--)
	{
		scanf("%d%d",&n,&k);
		printf("%lld\n",solve());
	}









    return 0;
}

 

你可能感兴趣的:(CodeForces上分,贪心)