编程之美-2.8 找到符合条件的整数

一、问题描述

任意给定一个正整数N,求一个最小正整数M(M>1),使得N*M的十进制形式只含1和0。

比如 N=99,M=1 122 334 455 667 789 ,N*M=111 111 111 111 111
111;

M就是当N=99时,符合条件的数

二、解题思路

考虑将问题转化为:找只含有0和1的能被N整除的最小正整数。可以看出这是和原问题等价的。

那么需要将0和1组成的所有数从小到大遍历吗?
这样的话,如果寻找的数是k位,则需要搜索2k-1个数才能得到结果。

这里采用的方式是在计算中保留%N的余数信息,避免不必要的计算。更形式化的论述:

假如已遍历了所有K位(X)十进制数,而且也搜索了T=10k(10的k+1位数的最小数),现在要考察所有k+1为数(Y)的情况。则

Y=X+T(即所有K进制的数+10K),如果我们将X按%N将空间分解,即将X分解成余数为(0~N-1)的等价类,则在搜索Y是只需要取X中的代表元素进行模运算,这样就将搜索时间从2K降到N。在具体实现时每个等价类中都保存最小的元素。

三、代码实现


#include<iostream>
#include<vector>
#include<string>
#define N 100213
using namespace std;
vector<vector<int> >BigIntVec;
void printNum(const vector<int>& tv){
//cout<<"print"<<endl;
int maxIndex=tv.back();
string numStr="";

for(int i=0;i<maxIndex+1;i++){
numStr+="0";
}
for(int i=0;i<tv.size();i++){
numStr[maxIndex-tv[i]]=‘1‘;
}
cout<<"找到的最小符合条件的数为:"<<endl;
for(int i=numStr.size()-1;i>=0;i--){
cout<<numStr[i];
}
cout<<endl;
}
void findNum(){
for(int i=0;i<N;i++){
vector<int>tt;
BigIntVec.push_back(tt);
}
BigIntVec[1].push_back(0);
int noUpdate=0;
for(int i=1,j=10%N;;i++,j=(j*10)%N){

bool flag=false;
if(BigIntVec[j].size()==0){
BigIntVec[j].push_back(i);
flag=true;
}

for(int k=0;k<N;k++){

if(BigIntVec[k].size()>0&&i>BigIntVec[k].back()){

int t=(k+j)%N;

if(BigIntVec[t].size()==0){

for(int tt=0;tt<BigIntVec[k].size();tt++){
BigIntVec[t].push_back(BigIntVec[k][tt]);
}
BigIntVec[t].push_back(i);
flag=true;
}
}

}

if(flag==false){
noUpdate++;
}else{
noUpdate=0;
}
if(BigIntVec[0].size()>0||noUpdate==N){

break;
}
}
if(BigIntVec[0].size()>0){
printNum(BigIntVec[0]);
}else{
cout<<"没有找到符合条件的数"<<endl;
}
}

int main(){
findNum();
system("pause");
return 0;
}

注:由于该问题涉及到的整数可能非常大,不能用内置类型int或long表示,因此程序中借助vector实现模拟整数。因为寻找的数只有1,0两种数字,为了节省空间,每个整数用vector<int>表示,vector每一元素保存1出现的位置。例如数字100101,的vector<int>表示为{0,2,5},即出现1的位置分别为第0,2,5位。

四、程序输出结果(输入N为:100213):

时间: 2024-11-05 06:14:06

编程之美-2.8 找到符合条件的整数的相关文章

编程之美2.8——找符合条件的整数

任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0. 如N=3,M=39,N*M=111. [思路] 这么难的思路打死我也想不到[email protected][email protected]|||||.. 将题目转换为,求一个数X,使得X%N=0且X的十进制表示只含有1和0. 维护一个“余数数组”,对于从0到N-1的每一个余数,都有相应的最小X: 高位可以利用低位的余数归队,X=10^k+Y(10的k次方,^表示次方)X%N=(10^k%N+Y%

编程之美2.8 | 找符合条件的整数

思路还是相当地巧妙. 求余数的话,(a+b)%n=(a%n+b%n)%n; 用vector来表示整数的话(出现1的位置),可以避免溢出. 注意第20行,在更新remainders[(j+r)%n]时,要确保每个remainders的每个序列都是递增的,不能存在相等的情况. 1 #include <time.h> 2 #include <math.h> 3 #include <stdlib.h> 4 5 using namespace std; 6 7 long long

编程之美——符合条件的整数

问题:给定整数N,求最小整数M,使得N*M的十进制表示中只含有1和0: 当M很大时,机器可能不能表示M,对问题转化:求以最小整数X,使得X的十进制表示中只含1和0,并且被N整除: 此问题必定有解:可参考:http://blog.csdn.net/spaceyqy/article/details/38337387 代码实现(具体思路参考编程之美或:http://www.cnblogs.com/jfcspring/p/3776388.html): 1 #include<iostream> 2 #i

编程之美 找出符合条件的整数

好不容易把内容看懂~ 最主要的一句话:只需要将10k%N的结果与余数信息数组里非空的元素相加,再去模N,看看会不会出现新的余数~ 时间太紧迫~先把自己写的代码贴上,以后再详解 1 int FindMin(int N) 2 { 3 if(N <= 1) 4 return N; 5 6 int* A = new int[N];//这个是记录模N余i之后的数值 7 8 memset(A, -1, sizeof(int) * N); 9 int factor = 1; 10 A[1] = 1; 11 1

第2章 数字之魅——找符合条件的整数

找符合条件的整数 问题描述 任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0. 解决这个问题首先考虑对于任意的N,是否这样的M一定存在.可以证明,M是一定存在的,而且不唯一.简单证明:因为 这是一个无穷数列,但是数列中的每一项取值范围都在[0, N-1]之间.所以这个无穷数列中间必定存在循环节.即假设有s,t均是正整数,且s<t,有 .于是循环节长度为t-s.于是10^s = 10^t.因此有:,所以 例如,取N=3,因为10的任何非负次方模3都为

【编程之美】2.8 找符合条件的整数

给定一个正整数N,求一个最小的正整数M(M > 1),使得N * M的十进制表示中只有0和1. 我的思路: 从最低位到最高位找M,每次使得乘积的最后面多一位符合0.1的条件. 那么先找能够让末尾数字变成0的备选项 举例若N的个位数是9  考虑从后面来的进位 c 让 x * 9 + c 的末尾是0或1 设个位数字为9 则eligibleNum中存储的数字eligibleNum[0][0] = 0 因为9 * 0 + 0 = 0 末尾符合0或1 eligibleNum[0][0] = 9 因为9 *

【编程之美】找符合条件的整数

任意给定一个正整数N,求一个最小的正整数M(M > 1),使得N*M的十进制表示形式里只含有1和0. 看了题目要求之后,我们首先想到从小到大枚举M的取值,然后再计算N*M,最后判断它们的乘积是否只含有1和0.大体思路可以用下面的伪代码实现: 1 for (M = 2; ; M++) 2 { 3 product = N * M; 4 if (hasOnlyOneAndZero(product)) 5 output N, M, product, and return; 6 } 但问题很快就出现了,什

编程之美---找符合条件的整数

题目:任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0. 解法:原问题转化为求一个最小的正整数X,使得X的十进制表示形式里只含有1和0,并且X被N整除.于是乎就成了遍历二进制整数一样遍历X的各个取值,但是如果X的最终结果又K位,则要循环搜索2K 次.因此,可以建立一个长度为N的“余数信息数组”,这个数组的第i位保留已经出现的最小的模N为i的X.用BigInt[i]可能很大,只须记下1的位置即可. 1 for(i=0;i<N;i++) 2 BigIn

【编程之美】快速寻找满足条件的两个数

能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解. 分析与解法 方法一:枚举 从数组中任取两个数字,判断是否满足条件. 显然时间复杂度为N(N-1)/2,即O(N2). 方法二:查找 我们可以把问题进行转化:对于任意数arr[i],查找sum-arr[i]是否在数组中. (1) 一般查找 在不做处理的情况下直接在数组中查找sum-arr[i]的时间复杂度为O(N),总时间复杂度仍为O(N2). (2) 折半查找 显然