Codeforces Round #268 (Div. 1) C. Hack it!(二分+尺取/构造,好题)

9 篇文章 0 订阅
5 篇文章 0 订阅

C. Hack it!
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Little X has met the following problem recently. 

Let's define f(x) as the sum of digits in decimal representation of number x (for example, f(1234) = 1 + 2 + 3 + 4). You are to calculate 

Of course Little X has solved this problem quickly, has locked it, and then has tried to hack others. He has seen the following C++ code: 

    ans = solve(l, r) % a;
    if (ans <= 0)
      ans += a;

This code will fail only on the test with  . You are given number  a, help Little X to find a proper test for hack.
Input

The first line contains a single integer a (1 ≤ a ≤ 1018).

Output

Print two integers: l, r (1 ≤ l ≤ r < 10200) — the required test data. Leading zeros aren't allowed. It's guaranteed that the solution exists.

Examples
input
46
output
1 10
input
126444381000032
output
2333333 2333333333333

题意:

定义f(x)为x在十进制下的各位数字之和。

给定a,需要你给出一个l,r(1 <= l <= r <= 1e200)使得(f(l) + ... +f(r))能被a整除。

题目确保有解。

(1 <= a <= 1e18)


题解:

姿势1:[一套尺取+二分连招]
令s(x) = f(1)+f(2)+…+f(x)。
我们只需找到s(R)%a = s(L-1)%a就美滋滋了
我们使用二分查询找到最小的且满足g(R)>=a
的值R, 接下来令L=1,然后跑一个双指针,调整
L,R的值即可。至于s(x)怎么求,我们把每一个
数位对答案的贡献加起来即可。

姿势2:[构造]
注意到f(x+1e18)=f(x)+1。
故s(x+1e18)=s(1e18)+s(x)+x。
即s(x+1e18)-s(x) = s(1e18)+x
 s(1e18)+x%a==0,x= a-s(1e18)%a
L = a-s(1e18)%a+1,R = L + 1e18- 1
于是一组合法解就神不知鬼不知觉地构造出来了
代码请有兴趣的读者自行完成~

方法1:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
ll get(ll x)
{
    ll ans=0;
    for(ll i=1;i<=x;i*=1ll*10)
    {
        int d=(x/i)%10;
        ll q=x/(1ll*10*i);
        ans+=i*q*45;
        rep(j,1,d) ans+=j*i;
        ll t=x-(x/i)*i;
        ans+=(t+1)*d;
    }
    return ans;
}

ll get1(ll x)
{
    ll ans=0;
    while(x)
    {
        ans+=x%10;
        x/=10;
    }
    return ans;
}

int main()
{
    ll a;
    scanf("%lld",&a);
    ll l=0,r=1e17,ans=-1;
    while(l<=r)
    {
        ll m=(l+r)/2;
        if(get(m)>=a)
            ans=m,r=m-1;
        else l=m+1;
    }
    l=1,r=ans;
    ll now=get(ans);
    while(now!=a)
    {
        if(now>a) now-=get1(l++);
        else if(now<a) now+=get1(++r);
    }
    printf("%lld %lld\n",l,r);
    return 0;
}




方法2:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
ll get(ll x)
{
    ll ans=0;
    for(ll i=1;i<=x;i*=1ll*10)
    {
        int d=(x/i)%10;
        ll q=x/(1ll*10*i);
        ans+=i*q*45;
        rep(j,1,d) ans+=j*i;
        ll t=x-(x/i)*i;
        ans+=(t+1)*d;
    }
    return ans;
}


int main()
{
    ll a;
    scanf("%lld",&a);
    ll t=get(1e17)%a;
    ll l=a-t+1,r=l+1e17-1;
    printf("%lld %lld\n",l,r);
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值