How to find the smallest number with just 0 and 1 which is divided by a given number?
The question equals to using 10i mod n (for each i, it can be used at most once) to get a sum m of n. It's like a knapsack problem or subset sum problem. In this way, dynamic programming will do the task.
In dynamic programming the complexity is O(k*n)
. k is the number of digits in answer. For n<105, this code works perfectly.
Code:
#include <stdio.h>
#define NUM 2000
int main(int argc, char* argv[])
{
signed long pow[NUM],val[NUM],x,num,ten;
int i,j,count;
for(num=2; num<NUM; num++)
{
for(i=0; i<NUM; pow[i++]=0);
count=0;
for(ten=1,x=1; x<NUM; x++)
{
val[x]=ten;
for(j=0; j<NUM; j++)if(pow[j]&&!pow[(j+ten)%num]&&pow[j]!=x)pow[(j+ten)%num]=x;
if(!pow[ten])pow[ten]=x;
ten=(10*ten)%num;
if(pow[0])break;
}
x=num;
printf("%ld\tdivides\t",x=num);
if(pow[0])
{
while(x)
{
while(--count>pow[x%num]-1)printf("0");
count=pow[x%num]-1;
printf("1");
x=(num+x-val[pow[x%num]])%num;
}
while(count-->0)printf("0");
}
printf("\n");
}
}
PS: This sequence in OEIS.
There's an O(n)-time (arithmetic operations mod n, really) solution, which is more efficient than the answer currently accepted. The idea is to construct a graph on vertices 0..n-1 where vertex i has connections to (i*10)%n and (i*10+1)%n, then use breadth-first search to find the lexicographically least path from 1 to 0.
def smallest(n):
parents = {}
queue = [(1 % n, 1, None)]
i = 0
while i < len(queue):
residue, digit, parent = queue[i]
i += 1
if residue in parents:
continue
if residue == 0:
answer = []
while True:
answer.append(str(digit))
if parent is None:
answer.reverse()
return ''.join(answer)
digit, parent = parents[parent]
parents[residue] = (digit, parent)
for digit in (0, 1):
queue.append(((residue * 10 + digit) % n, digit, residue))
return None
Nice question. I use BFS to solve this question with meet-in-the-middle and some other prunings. Now my code can solve n<109 in a reasonable time.
#include <cstdio>
#include <cstring>
class BIT {
private: int x[40000000];
public:
void clear() {memset(x, 0, sizeof(x));}
void setz(int p, int z) {x[p>>5]=z?(x[p>>5]|(1<<(p&31))):(x[p>>5]&~(1<<(p&31)));}
int bit(int p) {return x[p>>5]>>(p&31)&1;}
} bp, bq;
class UNIT {
private: int x[3];
public: int len, sum;
void setz(int z) {x[len>>5]=z?(x[len>>5]|(1<<(len&31))):(x[len>>5]&~(1<<(len&31)));}
int bit(int p) {return x[p>>5]>>(p&31)&1;}
} u;
class MYQUEUE {
private: UNIT x[5000000]; int h, t;
public:
void clear() {h = t = 0;}
bool empty() {return h == t;}
UNIT front() {return x[h];}
void pop() {h = (h + 1) % 5000000;}
void push(UNIT tp) {x[t] = tp; t = (t + 1) % 5000000;}
} p, q;
int n, md[100];
void bfs()
{
for (int i = 0, tp = 1; i < 200; i++) tp = 10LL * (md[i] = tp) % n;
u.len = -1; u.sum = 0; q.clear(); q.push(u); bq.clear();
while (1)
{
u = q.front(); if (u.len >= 40) break; q.pop();
u.len++; u.setz(0); q.push(u);
u.setz(1); u.sum = (u.sum + md[u.len]) % n;
if (!bq.bit(u.sum)) {bq.setz(u.sum, 1); q.push(u);}
if (!u.sum) {
for (int k = u.len; k >= 0; k--) printf("%d", u.bit(k));
puts(""); return;
}
}
u.len = 40; u.sum = 0; p.clear(); p.push(u); bp.clear();
while (1)
{
u = p.front(); p.pop();
u.len++; u.setz(0); p.push(u);
u.setz(1); u.sum = (u.sum + md[u.len]) % n;
if (!bp.bit(u.sum)) {bp.setz(u.sum, 1); p.push(u);}
int bf = (n - u.sum) % n;
if (bq.bit(bf)) {
for (int k = u.len; k > 40; k--) printf("%d", u.bit(k));
while (!q.empty())
{
u = q.front(); if (u.sum == bf) break; q.pop();
}
for (int k = 40; k >= 0; k--) printf("%d", u.bit(k));
puts(""); return;
}
}
}
int main(void)
{
// 0 < n < 10^9
while (~scanf("%d", &n)) bfs();
return 0;
}