HDU 5710 Digit-Sum (构造)

题意:

定义S(N) 为数字N每个位上数字的和。
在给两个数a,b,求最小的正整数n,使得 a×S(n)=b×S(2n)。

官方题解:

这道题目的结果可能非常大,所以我们直接枚举n是要GG的。

首先可以有这样的基础性结论:
设gcd(a,b)=g, 我们可以先使得b=b/g, a=a/g
S(n):S(2n)==b:a,那么我们有S(n):S(2n)=b:a。

然后,一个好的做法是,我们研究本质问题。
我们发现,如果一个digit是0~4,那么*2的效益是完全获得的。
如果一个digit的是5~9,那么*2后会损失9的收益。
a*S(n) == b*S(2n),

我们假设有l的长度是[0,4]范围,有L的长度是[5,9]范围
那么显然满足:
S(2n)=S(n)*2-L*9
替换一下——
a*S(n) == b*(2S(n)-L*9)
a*S(n) == 2b*S(n) -L*9*b
(2b-a)*S(n) == L*9*b
即——
9*b:2b-a = S(n):L
也就是说,我们得到了S(n)与L的比例关系。
然后模拟一遍即可。

怎么模拟呢?
我们不妨假设答案n仅有长度为L,且每一位都是5
然后得到了把数位和sum分撒出去。

对于sum余下的数值,我们依次加到尾巴上。
如果sum最后把长度为L的字串都填充为'9'之后,还有剩余,那么在前面贪心填充。

构造题一般是找规律。找到了就恍然大悟了,找不到就……我靠这题怎么这么难!

做题要大胆,细心。

代码:

#include <iostream>

using namespace std;

// a*s(n)=b*s(2n)
// a*s(n)=b*( 2*s(n)-9*l )
// (a-b*2)*s(n)=-b*9*l
// (b*2-a)/b*9=l/s(n)

int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
int ans[1005];
int main()
{
    int T;
    cin >> T;
    while (T--) {
        int a, b;
        cin >> a >> b;
        int l = b * 2 - a;
        int sn = b * 9;
        if (5 * l > sn || l < 0) {
            cout << "0" << endl;
            continue;
        }
        if (l == 0) {
            cout << "1" << endl;
            continue;
        }
        int gg = gcd(l, sn);
        l /= gg; sn /= gg;
        int idx = 0;
        sn -= 5 * l;
        for (int i = 0; i < l; ++i) {
            int add = min(4, sn);
            sn -= add;
            ans[idx++] = 5 + add;
        }
        while (sn) {
            int res = min(4, sn);
            ans[idx++] = res;
            sn -= res;
        }
        for (int i = idx-1; i >= 0; --i) cout << ans[i];
        cout << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wenruo/p/5562100.html