最小正整数n,可被d整除并且位数之和等于s

时间:2018-11-06 16:33:07

标签: number-theory

我在代码部队(http://codeforces.com/problemset/problem/1070/A)上发现了此问题,并且我试图了解发布的一种非常优雅的解决方案:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

int d,s;

struct node
{
    int mod,sum;
    char s[700];
    int len;
};

queue<node> Q;
bool v[512][5200];

int main()
{
    scanf("%d%d",&d,&s);
    Q.push({0,0,0,0});
    while(!Q.empty())
    {
        node a=Q.front();Q.pop();
        for(int i=0;i<10;i++)
        {
            node b=a;
            b.s[b.len++]=i+'0';
            b.mod=(b.mod*10+i)%d;
            b.sum+=i;
            if(v[b.mod][b.sum] || b.sum>s) continue;
            v[b.mod][b.sum]=1;
            if(b.mod==0&&b.sum==s)
            {
                puts(b.s);
                return 0;
            }
            Q.push(b);
        }
    }
    puts("-1");
    return 0;
}

我知道通过将数字添加到前缀并将它们放在队列中来完成树状搜索。搜索是这样的1,2,3,4 ...然后10,11,12 ... 20,21,22 ...等等。

我不了解以下停止条件:

if(v[b.mod][b.sum] || b.sum>s) continue;

很明显,如果数字的总和大于s,则当前路径不值得追求。但是,如果我们之前遇到一个数字,其余数和数字总和相同,那么丢弃路径的依据是什么?

一个例子是这样的: d = 13 s = 50

路径到达120时,它将触发条件,因为我们已经看到了数字3,该数字与120具有相同的余数,并且具有相同的数字总和。

1 个答案:

答案 0 :(得分:1)

使用示例120和3以及一些modular arithmetic,这很容易说明,为什么基于已经测试过3的事实来整理出120:

模块化算术中的加法和乘法定义为:

((a mod n) + (b mod n)) mod n = (a + b) mod n
((a mod n) * (b mod n)) mod n = (a * b) mod n

使用这些,我们可以证明,对于任何其他数字x,余数d都将保持不变:

(120 * 10 + x) mod d = ((120 mod d) * (10 mod d) + (x mod d)) mod d
(  3 * 10 + x) mod d = ((  3 mod d) * (10 mod d) + (x mod d)) mod d

因为我们知道3 mod d = 120 mod d,所以我们知道,如果我们用相同的附加数字测试它们,则上述两个术语将具有相同的余数。

但是它们的数字总和也相等,这意味着可以将相同的一组新数字应用于两个数字。因此,就问题而言,120和3是等效的,前者可以丢弃。