codefroces 486C Hack it! 数位dp+二分

      定义f(x)是x的各位数字之和(x十进制),定义g(x)=f(1)+f(2)+...f(x),给出a,求出一个区间l,r使得(g(r)-g(l-1) )%a==0.

      首先要想办法求出g(),求解g实际上就是一个数位dp了,然后求出一个最小的x使得g(x)>=a,然后令l=1,r=x,不断调整两个区间使得g(r)-g(l-1)==a,虽然复杂度有点不科学,但实际上调整的次数不会太多....

     

/*=============================================================================
#  Author:Erich
#  FileName:
=============================================================================*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r

using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=1ll<<60;
const double PI=acos(-1.0);
int n,m;
ll pw[19];
ll sum[20];
ll calc(ll x)
{
    if (x==0) return 0;
	return 45ll*x*pw[x-1];
}
ll find(ll k)
{
	ll x,y;
	int num[20];
	int m=0;
	while(k)
	{
		num[m]=k%10;
		m++;
		k/=10;
	}
	ll res=0;
	ll cnt=0;
	for (int i=0; i<m; i++)
	{
	    if (num[i])
	    {
                res+=calc(i)*num[i];
                res+=sum[num[i]-1]*pw[i];
                res+=num[i]*(cnt+1);
	    }
        cnt+=num[i]*pw[i];
	}
	return res;
}
int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);

	pw[0]=1;
	pw[1]=10;
	sum[0]=0;
	sum[1]=1;
	for (int i=2; i<=19; i++)
		pw[i]=pw[i-1]*10,sum[i]=sum[i-1]+i;
	ll x,y;
    ll a;
//    printf("%I64d\n",find(100000000000000000LL));
//    printf("%I64d\n",find(10000000000000000LL));
    while(~scanf("%I64d",&a))
    {
        ll l=0,r=100000000000000000LL;
        ll ansl,ansr;
        ll mid;
        while(l<r)
        {
            mid=(l+r)>>1;
            if (find(mid)>=a) r=mid;
            else l=mid+1;
        }
        ansl=1;
        ansr=l;
        x=find(ansl-1);
        y=find(ansr);
        while(y-x!=a)
        {
            if (y-x>a) ansl++;
            else ansr++;
            x=find(ansl-1);
            y=find(ansr);
        }
        printf("%I64d %I64d\n",ansl,ansr);
    }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值