atcoder AtCoder Regular Contest 084 D

来源:互联网 发布:关闭手机数据连接 编辑:程序博客网 时间:2024/06/04 18:06

传送门
思路:建立从1开始达到所有数的边,权值为位数和的差。最后dist[0]就是答案,代表最小的位数和能整除K。
相当于建立一个数x到x+1和x*10分别为1和0的边,最后找到最快到达的k的倍数,即答案。
写法1:spfa

#include<bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN = 1000005;struct node{    int from, to, w;} G[MAXN];int dist[MAXN];int head[MAXN];bool vis[MAXN];int cnt;void add(int u, int v, int w){    G[cnt].to=v;    G[cnt].w=w;    G[cnt].from=head[u];    head[u]=cnt++;}void spfa(int s){    memset(vis, false, sizeof(vis));    queue<int> q;    while(!q.empty())        q.pop();    vis[1]=true;    q.push(s);    dist[s]=0;    while(!q.empty())    {        int u=q.front();        q.pop();        vis[u]=false;        for(int i=head[u]; ~i; i=G[i].from)        {            int v=G[i].to;            if(dist[v]>dist[u]+G[i].w)            {                dist[v]=dist[u]+G[i].w;                if(!vis[v])                {                    vis[v]=true;                    q.push(v);                }            }        }    }}int main(){    int k;    scanf("%d", &k);    memset(head, -1, sizeof(head));    memset(dist, 0x3f,sizeof(dist));    cnt=0;    for(int i=0; i<k; ++i)    {        add(i,(i+1)%k, 1);        add(i, i*10%k, 0);    }    spfa(1);    printf("%d\n", dist[0]+1);    return 0;}

思路二:双端队列
学习一下, 可以重前后插入,然后取队头的数据结构。
首先优先插入x*10,因为权值为0,插在头部。x+1插入尾部。

#include<iostream>#include <cstdio>#include <algorithm>#include <queue>#include <cstring>using namespace std;typedef long long LL;const int MAXN = 100005;const LL inf = 0x3f3f3f3f;int main(void){    int k,v,u;    cin>>k;    vector<int> dp(k,1000);    dp[1] = 0;    deque<int> deq;    deq.push_front(1);    while(v = deq.front()){        deq.pop_front();        u = (v*10)%k;        if(dp[u] > dp[v]){            dp[u] = dp[v];            deq.push_front(u);        }        u = (v+1)%k;        if(dp[u] > dp[v]+1){            dp[u] = dp[v]+1;            deq.push_back(u);        }    }    cout<<dp[v]+1<<endl;}
原创粉丝点击