倍数
对于一个正整数a来说,它的各位数字之和就是它的价值,例如a=133,那么a的价值=1+3+3=7。
你需要找到一个价值最小的正整数b, 且b是k的倍数, 输出满足条件的最小价值。
输入格式
一个整数k。2<=k<=100000。
输出格式
一个正整数。
输入/输出例子1
输入:
6
输出:
3
样例解释
12是6的倍数,且12的价值是3。
再也找不出价值小于3的正整数,使得该正整数是6的倍数。
1.涉及到整除的东西,不是除法就是模,要相结合
2.不是一定有图才是最短路,类似于改进,用优的改进劣的,都可以往这方面想想。
ljx/我
这题和图看着没关系,实则关系密切,刚开始一眼看肯定是暴力,但是必然会炸,于是就有了一些巧妙方法
余数(%k)作为dis[]数组的下标,然后它对应的价值就是
各位数字之和,例如k=6,那么初始化dis[0]=6。
接着,我们就在这个价值后面加入0~9这几个数,变成60,61,
62......然后再去模k,尝试改变dis[]的价值,取一个更优解,这就是一个“松弛”操作 啊!!!
例如刚开始 dis[2]=1e9(假设的,实际上并不是),然后6后面加2,发现变成62,余数2,价值8,8<dis[2],更新
#include <bits/stdc++.h> using namespace std; const int N=100005; int k, dis[N], vis[N]; queue<int> q; int main() { scanf("%d", &k); memset(dis, 63, sizeof dis); for (int i=1; i<=k; i++) dis[i%k]=i, q.push(i%k); while (!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for (int i=0; i<=9; i++) { int v=(u*10+i)%k; if (dis[v]>dis[u]+i) { dis[v]=dis[u]+i; if (!vis[v]) vis[v]=1, q.push(v); } } } printf("%d", dis[0]); return 0; }
csh(搬)
我们希望的是这个最小值是不断改进出来的,这样就可以避免因为大范围寻找而浪费时间。改进让我们可以联想到最短路。但是怎么联系到最短路呢?b是k的倍数,就说明b%k==0,我们可以从余数开始思考。 拿这个样例来举例,它的余数就有1,2,3,4,5,0。一开始我们把这些余数所对应的正整数a设为1,2,3,4,5,6(这是符合情况下且最显而易见的)。接下来,利用价值b去改进,价值是所有数位加起来,10b和b的价值是一样的,不过是多了一个0;10b+1就比b的价值多了1;那么利用这个性质,从1开始(从小的价值开始改进,保证改变的会变小),用110+0,110+1,110+2........模k,让此时的价值对所对应余数原本的价值进行改进,改进完的就去改进别人。 例如,110+0=10,10%6=4,那么余数为4的数的价值就可以更新,这个的价值最小为1;1*10+1=11,11%6=5,那么余数为5的数的价值就可以更新,这个的价值最小为2.
前面说“一开始我们把这些余数所对应的正整数a设为1,2,3,4,5,6(这是符合情况下且最显而易见的)”,这里只设置1-9,因为其他的都可以通过*10+x得到。
#include<bits/stdc++.h> using namespace std; int k,mp[100000]; struct cmp{ bool operator()(const int &p1,const int &p2)const{ return p1>p2; } }; priority_queue<int,vector<int>,cmp>pq; int main(){ scanf("%d",&k); memset(mp,0x3f,sizeof(mp)); for(int i=1;i<=min(k,9);i++) mp[i%k]=i; pq.push(1); while(!pq.empty()) { int x=pq.top(); pq.pop(); for(int i=0;i<=9;i++) { int t=x*10+i; if(mp[t%k]>mp[x]+i) { mp[t%k]=mp[x]+i; pq.push(t%k); } } } cout<<mp[0]; return 0; }