hdu搜索
hdu 4294
题意: 给出一个n(n<=10000)和k(2<=k <=10),现在想求出一个数M,M是n的倍数,现在让M用k进制表示。
要求: 表示成k进制后所含的不同数字的数目最小。如果有多组解输出值最小的一组。
思路: 首先有一个定理,就是在k进制下最多需要两个不同的数字就可以表示出n的整数倍。
下面简单证明一下。aaa......aaaaa mod n可以得到的数最多有n个,当这个串很长之后肯定有两个数mod n后是想等的,将这两个数相减就是n的倍数,但是这里雀只有两个数字。 由此得证,最多只需要两个数字就行。
接下来首先看一个数字行不行。如果一个数字就行的话那么就直接得出结果。 否则的话就枚举两个数字,我先枚举的是首位的数字,然后再枚举另外一个数字。这里用bfs, 表示对bfs理解的还不够啊。 类似于最短路,开始的时候wa了好几次,后来知道是bfs往后添加数的顺序出现了问题,应该现往后添加小的,再往后添加大的,这样才能保证解的最优性。
AC代码:
View Code
#include <iostream> #include <cstring> #include <cstdio> #include <string> #include <algorithm> #include <queue> using namespace std; const int N = 11100, INF = 1<<29; struct { int u,num; } p1, p2; int n, k, f[N], ans[N], pre[N], now[N]; queue<int>q; void solve() { int ans1 = INF, tp, t; p1.num = INF; for(int i=1; i<k; i++) { tp = 0; for(int j=1; j<=n+1; j++) { tp *= k; tp += i; tp %= n; if(tp == 0) { if(p1.num > j) { p1.u = i; p1.num = j; break; } } } } if(p1.num != INF) { for(int i=1; i<=p1.num; i++) printf("%d",p1.u); printf("\n"); return ; } for(int i=1; i<k; i++) { for(int j=0; j<k; j++) { while(!q.empty()) q.pop(); memset(f, 0, sizeof(f)); pre[i%n] = 0; f[i%n] = 1; int u, v; q.push(i%n); while(!q.empty()) { u = q.front(); q.pop(); if(u == 0) break; if(i < j) t = i; else t = j; v = (u*k + t)%n; if(!f[v]) { f[v] = f[u]+1; pre[v] = u; if(v == 0) break; q.push(v); } if(i < j) t = j; else t = i; v = (u*k + t)%n; if(!f[v]) { f[v] = f[u]+1; pre[v] = u; if(v == 0) break; q.push(v); } } u = 0; for(int w=f[0]; w>0; --w) { v = pre[u]; now[w] = ((u-v*k)%n+n)%n%k; u = v; } if(f[0] < ans1 && f[0] != 0) { ans1 = f[0]; memcpy(ans,now,sizeof(ans)); } else if(f[0] == ans1 && f[0] != 0) { for(int w=1; w<=ans1; w++) { if(ans[w] != now[w]) { if(now[w] < ans[w]) { memcpy(ans,now,sizeof(ans)); } break; } } } } } for(int i=1; i<=ans1; i++) { printf("%d",ans[i]); } printf("\n"); } int main() { while(scanf("%d%d", &n, &k) != EOF) { solve(); } }


浙公网安备 33010602011771号