生成最小余数序列


21

每个数字都可以使用无限长的余数序列表示。例如,如果我们把7号,并执行7mod2,那么7mod3,那么7mod4,依此类推,我们得到的1,1,3,2,1,0,7,7,7,7,....

但是,我们需要尽可能的余数子序列,该子序列仍可用于将其与所有较低的数字区分开。再次使用7 [1,1,3]是最短的子序列,因为所有先前的子序列都不以开头[1,1,3]

0: 0,0,0,0...
1: 1,1,1,1...
2: 0,2,2,2...
3: 1,0,3,3...
4: 0,1,0,4...
5: 1,2,1,0...
6: 0,0,2,1...

请注意,[1,1] 它不能代表7,因为它也可以代表1。但是,您应该[1]输入1。

输入输出

您的输入是一个非负整数。您必须输出如上定义的余数的最小长度序列或序列。

测试用例:

0: 0
1: 1
2: 0,2
3: 1,0
4: 0,1
5: 1,2
6: 0,0,2
7: 1,1,3
8: 0,2,0
9: 1,0,1
10: 0,1,2
11: 1,2,3
12: 0,0,0,2
30: 0,0,2,0
42: 0,0,2,2
59: 1,2,3,4
60: 0,0,0,0,0,4
257: 1,2,1,2,5,5
566: 0,2,2,1,2,6,6
1000: 0,1,0,0,4,6,0,1
9998: 0,2,2,3,2,2,6,8,8,10
9999: 1,0,3,4,3,3,7,0,9,0

如果您感兴趣的话,这是前10,000个序列(行号偏移1)。

这是一个,因此请以您喜欢的语言使其尽可能短。假的奖励积分可以快速解决任何问题!



@nimi我们在聊天中谈到了这一点,因此我决定序列必须至少包含1个元素。
内森·美林

1
我很惊讶您没有将其限制为主要余数。
尼尔

如果将输出返回到列表中可以吗?
R. Kap

@neil,我也认为,但是由于余数与复合数字不同,所以我投票决定保留它
Nathan Merrill

Answers:


5

Mathematica,60 53字节

#~Mod~FirstCase[2~Range~#&/@Range[#+2],x_/;LCM@@x>#]&

有点快(它在约0.1秒内处理10000,但可能会耗尽100000的内存)。

该代码将引发错误,但可以正确计算结果。

说明

我们在聊天的前面已经发现,所需除数始终可以确定为最短列表,{1, 2, ..., n}其最小公倍数超过输入。一个简短的理由说明为什么:如果LCM小于输入,那么从输入中减去LCM会使所有除数保持不变,因此表示形式不是唯一的。但是,对于小于LCM的所有输入,余数将是唯一的,否则,具有相等余数的两个数字之间的差将是所有除数的较小倍数。

至于代码……像往常一样,打高尔夫球的Mathematica的阅读顺序有点有趣。

Range[#+2]

这为我们提供[1, 2, 3, ..., n+2]了输入列表n。的+2是,以确保其工作正常进行01

2~Range~#&/@...

在此列表2~Range~#上映射(用于的语法糖Range[2,#]),因此我们得到

{{}, {2}, {2,3}, ..., {2,3,...,n+2}}

这些是候选除数列表(当然,总的来说,这比我们需要的要多得多)。现在,我们找到其中第一个其LCM超过输入的值:

FirstCase[...,x_/;LCM@@x>#]

更多语法:x_一种匹配任何列表并调用它的模式x。该/;附连到该模式的条件。这种情况是LCM@@x>#哪里@@ 适用的功能列表,即LCM@@{1,2,3}手段LCM[1,2,3]

最后,我们利用事实,简单地得到所有余数,即,如果其中一个参数是列表(或者它们都是相同长度的列表ModListable,它将自动映射到列表:

#~Mod~...

5

果冻,14 字节

‘Ræl\>iṠ2»2r⁸%

这利用了一个事实,即线性同余系统的解(如果有的话)是模的LCM的唯一模。在线尝试!验证所有测试用例

怎么运行的

‘Ræl\>iṠ2»2r⁸%  Main link. Argument: n

‘               Increment; yield n+1.
 R              Range; yield [1, ..., n+1].
  æl\           Cumulatively reduce by LCM.
                This yields [LCM(1), ..., LCM(1, ..., n+1)].
     >          Compare all LCMs with n.
      iṠ        Find the first index of sign(n).
                This yields the first m such that LCM(2, ..., m) > n if n > 0, and
                0 if n == 0.
        2»      Take the maximum of the previous result and 2, mapping 0 to 2.
          2r    Yield the range from 2 up to and including the maximum.
            ⁸%  Compute n modulo each integer in that range.

5

MATL,24字节

感谢@nimi指出此答案的先前版本中的错误(现已更正)

Q:qtQ!\t0Z)tb=YpsSP2):Q)

对于两个最大的测试用例,这在联机编译器中的内存不足(但是它在具有4 GB RAM的计算机上工作)。

在线尝试!

说明

这以简单的方式应用了定义。对于输入n它计算包含2D阵列mod(p,q)p0nq1n+1。每个p都是一列,每个q都是一行。例如,使用输入,n=7此数组为

0 0 0 0 0 0 0 0
0 1 0 1 0 1 0 1
0 1 2 0 1 2 0 1
0 1 2 3 0 1 2 3
0 1 2 3 4 0 1 2
0 1 2 3 4 5 0 1
0 1 2 3 4 5 6 0
0 1 2 3 4 5 6 7

现在,将最后一列(包含的其余部分)n与该数组的每一列进行逐元素比较。这产生

1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1
0 1 0 0 1 0 0 1
0 0 0 1 0 0 0 1
0 0 1 0 0 0 0 1
0 1 0 0 0 0 0 1
1 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1

其中1表示平等。最后一列显然等于其自身,因此包含所有列。除了最后一列外,我们需要找到初始数最多的列,并记下初始数m。(在这种情况下,它是第二列,其中包含m=3初始列)。为此,我们计算每列的累积乘积:

1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1
0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1

然后每一列的总和

1 3 1 2 1 2 1 8

然后以不递增的方式排序,并采用第二个值,即3。这是所需的m,它指示我们需要选择多少个余数。

Q:q    % take input n implicitly. Generare row array [0 1 ... n]
tQ!    % duplicate. Transform into column array [1; 2; ...; n-1]
\      % modulo, element-wise with broadcast. Gives the 2D array
t0Z)   % duplicate. Take last column
tb     % duplicate, bubble up
=      % test for equality, element-wise with broadcast
Yp     % cumumative product of each column
s      % sum of each column. This gives the number of initial coincidences
SP2)   % sort in decreasing order and take second value: m
:Q     % generate range [2 3 ... m+1]
)      % apply as index into array of remainders of n. Implicitly display

4

果冻13 11 字节

r¬µ%€R‘$ḟ/Ṫ

这不会赢得任何速度布朗尼点数... 在线尝试!或者验证较小的测试用例

怎么运行的

r¬µ%€R‘$ḟ/Ṫ  Main link. Argument: n

r¬           Range from n to (not n).
             This yields [n, ..., 0] if n > 0 and [0, 1] otherwise.

  µ          Begin a new, monadic chain. Argument: A (range)

       $     Combine the previous two links into a monadic chain:
     R         Range; turn each k in A into [1, ..., k] or [] if k == 0.
      ‘        Increment to map k to [2, ..., k+1].
   %€        Take each k in A modulo all the integers in the 2D list to the right.
        ḟ/   Reduce by filter-not; sequentially remove all remainder sequences of
             n-1, ..., (not n) from the remainder sequences of n.
          Ṫ  Tail; take the last remainder sequence.
             This gives the shortest sequence for descending A and the longest one
             (i.e., [0]) for ascending A.

为什么要包括两个答案???
暴民埃里克(Erik the Outgolfer)'16年

因为它们是两种完全不同的方法。尽管此字段短了3个字节,但另一个实际上足够快来计算所有测试用例。
丹尼斯

如果我是你,我不会做的……除非是上下表决权。
暴民埃里克

不同的语言/方法会有不同的答案。那是我的第一个元问题。
丹尼斯

3

Python 3.5、117 95 78字节

import sympy
r=lambda n,m=2,M=1,*l:M>n and l or r(n,m+1,sympy.lcm(m,M),*l,n%m)

需要Python 3.5和sympy(python3 -m pip install --user sympy)。感谢@Dennis通知我,Python 3.5允许*l使用默认参数进行操作。


使用SymPy 0.7.5,您可以缩短M>n and ll*(M>n)
丹尼斯

3

Python 2,73 70 69 65字节

i=l=1
n=input()
while l<=n|1:
 i+=1;a=l;print n%i
 while l%i:l+=a

完整的程序。@Dennis通过改进处理零的方式节省了4个字节。


3

哈斯克尔,66 60 51 50字节

f i=mod i<$>[2..2+sum[1|l<-scanl1 lcm[2..i],l<=i]]

用法示例:f 42->[0,0,2,2]。这是@MartinBüttner的答案中描述的算法。

我将保留以前的版本以供参考,因为它非常快:

Haskell,51个字节

f i=mod i<$>[[2..x]|x<-[2..],foldl1 lcm[2..x]>i]!!0

花费0.03s f (10^100)我的5岁笔记本电脑。

编辑:@xnor找到了要保存的字节。谢谢!


通过计数索引直到lcm太高来保存字节:h i=mod i<$>[2..2+sum[1|l<-scanl1 lcm[2..i],l<=i]]
xnor

2

Pyth,51字节 66字节

IqQZ[Z).q)IqQ1[1))IqQ2,0 1))FdhhQJu/*GHiGHtUd1I>JQVQ aY%QhN)<tYd.q

试试看!

许多更高速的39字节版本(不用于0-2工作):

FdhhQJu/*GHiGHtUd1I>JQVtd aY%QhN)<tYd.q

它似乎适用于10 10 3之类的荒谬数字

注意:此答案不适用于0、1和2。已 修复!


2

JavaScript(ES6),81 77字节

f=(n,r=[n%2],l=i=2,g=(j,k)=>j?g(k%j,j):k)=>l>n?r:f(n,[...r,n%++i],i/g(i,l)*l)

这将递归地建立答案,直到LCM超过原始数字为止。当然,GCD也是递归计算的。

编辑:由于@ user81655,节省了4个字节。


@ user81655这简直就是徒手……
Neil

2

Ruby,52个字节

->n{m=t=1;a=[];(a<<n%m)until n<t=t.lcm(m+=1);a<<n%m}

该解决方案检查m从2开始的所有可能的值,该值是使序列唯一的余数。使最后一个m唯一的因素不是其余部分本身,而是那个m是最小范围的最后一个成员,(2..m)其中最小公倍数(LCM)大于该范围n。这是由于中国余数定理,要唯一地确定余数n是多少,这些余数的LCM必须大于n(如果n从中选择(1..n);如果n从中选择a..b,则LCM仅需大于b-a)。

注意:我把a<<n%m代码放在末尾,因为until n<t=t.lcm(m+=1)之前短路a已收到最后一个使其唯一的元素。

如果有人有任何高尔夫球建议,请在评论中或在PPCG聊天中让我知道

开球:

def remainder_sequence(num)
  # starting with 1, as the statements in the until loop immediately increments divisor
  divisor = 1
  # starts with 1 instead of 2, as the statements in the until loop
  # immediately change product to a new lcm
  product = 1
  remainders = []

  # this increments divisor first then checks the lcm of product and divisor
  # before checking if num is less than this lcm
  until num < (product = product.lcm(divisor = divisor + 1))
    remainders << num % divisor
  end

  # until always short circuits before the last element is entered
  # so this enters the last element and returns
  return remainders << num % divisor
end


1

Python的3.5,194 181 169 152 149 146字节:

感谢@ Sherlock9为2个字节!

def r(o,c=0):
 y=[[j%i for i in range(2,100)]for j in range(o+1)]
 while 1:
  c+=1;z=y[-1][:c]
  if z not in[f[:c]for f in y[:-1]]:break
 print(z)

完美运行,而且速度很快。计算100000输出的最小余数序列[0, 1, 0, 0, 4, 5, 0, 1, 0, 10, 4, 4]仅需约3秒钟。它甚至能够计算出输入1000000(一百万),输出的顺序,[0, 1, 0, 0, 4, 1, 0, 1, 0, 1, 4, 1, 8, 10, 0, 9]大约花费了60秒。

说明

基本上,这个函数首先创建一个列表的东西,y与所有j mod i地方j的范围是每一个整数0=>7(包括7)i在上述范围内的每个整数0=>100。然后,程序进入无限while循环,将yy[:-1:])的第一个到倒数第二个子列表中每个子列表的相同数量的内容y[-1]与list 的最后一个子列表()中的相同数量的项目进行比较y。当子表y[-1]不同的比任何其他子列表,循环被打破了,并返回正确的最小剩余序列。

例如,如果输入为3,y则将为:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]]

然后,当它进入while循环时,它将list中的每个子列表y[:-1:]与sublist中相同数量的项目进行比较y[-1]。例如,它将首先比较[[0],[1],[0]][1]。自从上次子列表中的其余部分y,它将继续,然后比较[[0,0],[0,1],[0,2]][1,0]。由于[1,0]现在不在y 该特定顺序的其余部分中,因此这是最小的提示序列,因此[1,0]可以正确返回。


要保存字节,y[:c:]y[:c]
Sherlock9

0

C89,105个字节

g(a,b){return b?g(b,a%b):a;}main(n,m,M){scanf("%d",&n);for(m=M=1;(M=++m*M/g(m,M))<=n;)printf("%d ",n%m);}

使用编译(带有警告)gcc -std=c89。在stdin上取一个数字,并在stdout上输出用空格分隔的余数序列。


1
当n = 0时,这不会打印任何内容
xsot

0

C,89字节

a,i=2;main(l,n){for(n=atoi(gets(n))?:!puts(n);n/l;printf("%d ",n%i++))for(a=l;l%i;l+=a);}

用gcc编译。在线尝试:n = 59n = 0

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.