【AtCoder】Small Multiple 思维题

D - Small Multiple


Time limit : 2sec / Memory limit : 256MB

Score : 700 points

Problem Statement

Find the smallest possible sum of the digits in the decimal notation of a positive multiple of K.

Constraints

  • 2≤K≤105
  • K is an integer.

Input

Input is given from Standard Input in the following format:

K

Output

Print the smallest possible sum of the digits in the decimal notation of a positive multiple of K.


Sample Input 1

Copy

6

Sample Output 1

Copy

3

12=6×2 yields the smallest sum.


Sample Input 2

Copy

41

Sample Output 2

Copy

5

11111=41×271 yields the smallest sum.


Sample Input 3

Copy

79992

Sample Output 3

Copy

36

这题的意思是给定一个k,求k的倍数中数位和的最少值

比如k=6,则k的倍数分别为6,12,18,其数位和分别是6,3,9,所以输出数位和3

我们首先这样考虑,对于暴力肯定是不行的,有可能答案是k*10000000那个数位和才最小

任何一个数可通过下面两种操作获得:

1、在一个数上+1,此时数位和+1(暂时不考虑原数字为9的情况,后面会说到原因)

2、在一个数上*10,此时数位和+0

之所以不考虑原数字为9的情况,因为任何一个数加10次+1的代价远远大于直接*10的操作(直接*10代价为0,并且结果相同)

所以考虑双向队列解决

从起始数字为1开始,此时数位和为1

不断进行上述操作,并且实时更新他们的代价(就是数位和)

注意vis标记,因为第一次出现的一定是余数为这个数的这一类数种最小的数位和

比如10%3=1,此时vis【1】=0,表示这是第一次出现,那么就是说所有k的倍数+1的这类数字中数位和最小就是这个

双向队列保证了先出现的一定是最小的=w=

以下是代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int vis[1000005];
struct forma
{
    long long first,second;
}stu;
int main()
{
    int k;
    while(~scanf("%d",&k))
    {
        memset(vis,0,sizeof(vis));
        deque<forma>d;
        d.push_front((forma){1,1});
        while(!d.empty())
        {
            stu=d.front();
            d.pop_front();
            if(vis[stu.first])
                continue;
            vis[stu.first]=1;
            if(stu.first==0)
            {
                printf("%lld\n",stu.second);
                break;
            }
            d.push_front((forma){stu.first*10%k,stu.second});
            d.push_back((forma){(stu.first+1)%k,stu.second+1});
        }
    }
}

以下是官方解释(其实我没怎么看懂TvT)

      全ての正整数は、1 から始めて、以下の 2 つの操作を繰り返すことで作ることができます。 • 今の数に 1 を足す。このとき、各桁の和は 1 増える。(1 の位が 9 のときはこの限りではあ りませんが、この問題を解くにあたっては考慮しなくていいことをあとで示します) • 今の数を 10 倍する。このとき、各桁の和は変わらない。 さて、全ての正整数を頂点とし、以上の操作の「今の数」から「新しい数」に辺をはったグラフ を考えます。求めるべきは、1 から K の倍数のうちのいずれかへの、このグラフ上での最短経路 長に 1 を足したものです。 

      このままでは頂点数は無限ですが、辺のはられ方を考えれば、各正整数に対応する頂点たちは modK で同一視できることが分かります。よって、各頂点を modK で同一視した K 頂点のグラ フ上で、1 から 0 への最短路を求めればよく、これは 01BFS を用いることで O(K) 時間で求める ことができます。1 の位が 9 の整数に 1 を足す遷移は、最短路のアルゴリズムを思い出せば行き 先の頂点がすでに訪れられていることがわかるので、特別に扱う必要はありません。 なお、01BFS とは、deque (両端キュー) を用意し、コスト 0 の辺の遷移は deque の先頭に、1 の辺の遷移は deque の末尾に要素を追加することによる、幅優先探索のアルゴリズムです。

猜你喜欢

转载自blog.csdn.net/qq_41548233/article/details/81393150