codeforces1120E The very same Munchhausen

190 篇文章 2 订阅
24 篇文章 0 订阅

题面

题意

给出一个正整数a,问是否存在一个正整数n,满足 S ( a ∗ n ) = S ( n ) / a S(a*n)=S(n)/a S(an)=S(n)/a n &lt; = 1 0 500000 n&lt;=10^{500000} n<=10500000
S ( x ) S(x) S(x)表示x各个数位的数字和。

做法

首先可以考虑把n分成多个部分,使n形如 b 1 + b_1+ b1+"0000" + b 2 + +b_2+ +b2+“0000” + b 3 . . . . . . b k +b_3......b_k +b3......bk
这样每一部分就相互独立了,只要满足 ∑ i = 1 k a ∗ S ( a ∗ b i ) − S ( b i ) = 0 \sum_{i=1}^{k}a*S(a*b_i)-S(b_i)=0 i=1kaS(abi)S(bi)=0即可。
我们可以根据 a ∗ S ( a ∗ b i ) − S ( b i ) = 0 a*S(a*b_i)-S(b_i)=0 aS(abi)S(bi)=0的正负将 b i b_i bi分成两类,要求这两类的和的绝对值相等。
因为500000很大,所以其实在大多数的情况下,只要满足等式,一般都不会超过范围。
所以可以让每类 b i b_i bi分别相等,这样我们只要找到两个数 x , y x,y x,y,使 a ∗ S ( a ∗ x ) − S ( x ) &gt; 0 a*S(a*x)-S(x)&gt;0 aS(ax)S(x)>0 a ∗ S ( a ∗ y ) − S ( y ) &lt; 0 a*S(a*y)-S(y)&lt;0 aS(ay)S(y)<0,然后 x , y x,y x,y再各自反复多次即可。
不难发现 x = 1 x=1 x=1肯定符合条件( a = 1 a=1 a=1时要特判)。
现在就要找到满足 a ∗ S ( a ∗ y ) − S ( y ) &lt; 0 a*S(a*y)-S(y)&lt;0 aS(ay)S(y)<0的y。
显然要让 S ( a ∗ y ) S(a*y) S(ay)尽可能小,那我们就可以考虑让它大于等于 1 0 i 10^i 10i,且尽可能的接近 1 0 i 10^i 10i
可以考虑枚举i,令 y = ⌈ 1 0 i s ⌉ y=\lceil \frac{10^i}{s} \rceil y=s10i,然后看看是否满足 a ∗ S ( a ∗ y ) − S ( y ) &lt; 0 a*S(a*y)-S(y)&lt;0 aS(ay)S(y)<0,如果满足计算此时的总长度是否小于等于500000,满足则输出,否则继续,注意特判一下a是 1 0 i 10^i 10i的因数的情况。
这个构造n的方案显然不是使n最小的,但是就此题 n &lt; = 1 0 500000 n&lt;=10^{500000} n<=10500000来说,已经足够了。

代码

#include<bits/stdc++.h>
#define ll long long
#define Z 5
#define MN 500000
#define N 500100
using namespace std;

ll a,g,A,B,sum;
string num,zero,ans;

inline ll gcd(ll u,ll v)
{
    for(;v;)
    {
	u%=v;
	swap(u,v);
    }
    return u;
}

inline ll S(ll u)
{
    ll res=0;
    for(;u;u/=10) res+=u%10;
    return res;
}

int main()
{
    ll i,j,tmp,t;
    for(i=1;i<=Z;i++) zero+='0';
    cin>>a;
    if(a==1)
    {
	puts("1");
	return 0;
    }
    B=S(a)*a-1;
    for(i=0,tmp=1;tmp;i++)
    {
	if(num[num.size()-1]!='9' && a*(S(a-tmp)+1)<sum+1)
	{
	    A=sum+1-a*(S(a-tmp)+1);
	    g=gcd(A,B);
	    if((A/g)*(Z+1)+(B/g)*(Z+num.size())<=MN)
	    {
		num[num.size()-1]++;
		break;
	    }
	}
	tmp=tmp*10;
	t=tmp/a;
	sum+=t;
	if(num.size() || t) num+=t+'0';
	tmp%=a;
    }
    if(!tmp)
    {
	if(a>sum)
	{
	    puts("-1");
	    return 0;
	}
	else if(a==sum)
	{
	    cout<<num;
	    return 0;
	}
	A=sum-a;
	g=gcd(A,B);
    }
    for(i=1;i<=(B/g);i++) ans+=num+zero;
    for(i=1;i<=(A/g);i++) ans+="1"+zero;
    cout<<ans;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值