6616: Small Multiple
时间限制: 1 Sec 内存限制: 512 MB
提交: 407 解决: 60
[提交] [状态] [讨论版] [命题人:admin]
题目描述
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 is given from Standard Input in the following format:
K
输出
Print the smallest possible sum of the digits in the decimal notation of a positive multiple of K.
样例输入
6
样例输出
3
提示
12=6×2 yields the smallest sum.
来源/分类
题意:一个数字k,要求找到一个数为k的倍数使得其各位数之和加起来最小。
小结:思路是种很奇妙的东西,不可思议。
SPFA:
可以从 x = i ,,分别向X+1和X*10分别建立一条权值为1和0的有向单边,因为如果是考虑数位和的话,+1表示数位和+1,而*10则数位和是不变的。然后跑一遍最短路,答案就是1到k的倍数的最短路,在这里如果大于k我们要modk,这样1到0的最短路就是1到k的倍数的最短路就是答案。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+10;
int head[maxn];
int vis[maxn];
ll dis[maxn];
int cnt;
struct edge{
int u,v,w;
int next;
}edge[maxn*2];
void add(int u,int v,int w)
{
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void spfa(int sta)
{
queue<int>Q;
Q.push(sta);
vis[sta]=1;
dis[sta]=0;
while(!Q.empty())
{
int now=Q.front();
Q.pop();
vis[now]=0;
for(int i=head[now];i != -1;i=edge[i].next)
{
int w=edge[i].w;
int son=edge[i].v;
if(dis[now]+w<dis[son])
{
dis[son]=dis[now]+w;
if(!vis[son])
{
Q.push(son);
vis[son]=1;
}
}
}
}
}
int main()
{
int k;
cnt = 0;
scanf("%d",&k);
memset(head,-1,sizeof(head));
for(int i=0;i <= k;i++)
{
vis[i]=0;
dis[i]=1e16+7;
}
for(int i = 0;i < k;i++)
{
add(i,(i+1)%k,1);
// cout<<i<<" "<<(i+1)%k<<endl;
add(i,(i*10)%k,0);
// cout<<i<<" "<<(i*10)%k<<endl;
}
spfa(1);
printf("%lld\n",dis[0]+1);
}
双端队列deque
第一次接触双端队列,这种队列既可以当栈也可以当队列用,但是在实际应用中用的并不如队列跟栈多。它即可已从头操作也可以从尾部操作,包括了队列和栈的所有性质。
本题中我们有限考虑因为x*10大代价是0,所以肯定会优先考虑所以就需要在头部插入x*10在尾部插入x+1,这样可以保证一直最小代价在最前面,那么访问到0(k的倍数)就表示当前是最小的代价输出即可。
deque <int> q
q.front()//从头部取元素 q.back()//从尾部取元素
q.pop_front()//头部出一个 q.pop_back//尾部出一个
q.push_front()//头部插入 q.push_back()//尾部插入
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define FIN freopen("D://code//in.txt", "r", stdin)
#define ppr(i,x,n) for(int i = x;i <= n;i++)
#define rpp(i,n,x) for(int i = n;i >= x;i--)
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
inline int read() {//读入挂
int ret = 0, c, f = 1;
for(c = getchar(); !(isdigit(c) || c == '-'); c = getchar());
if(c == '-') f = -1, c = getchar();
for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
if(f < 0) ret = -ret;
return ret;
}
typedef pair<int , int> P;//第一个表示mod k的的大小0就是k的倍数,第二个表示到这个状态的最短。
bool vis[maxn];
int main()
{
IO;
int k;cin>>k;
memset(vis,false,sizeof(vis));
deque <P> Q;
Q.push_back(make_pair(1,1));//初始1,1压入
while(!Q.empty())
{
P x = Q.front(); Q.pop_front();
if(vis[x.first]) continue;//当前状态之前已经达到过
vis[x.first] = true;
if(x.first == 0){printf("%d\n",x.second);break;}//找到最小的k的倍数的数位和
int first = x.first,second = x.second;
Q.push_front(make_pair(first*10%k,second));
Q.push_back(make_pair(first+1%k,second+1));
}
return 0;
}