Digital River(最快捷的解决方案)


9

这是我的第一个问题,所以我希望它顺利进行。

背景:

您可能正在考虑的不是河流。问题围绕数字河流的概念展开。数字河流是数字的序列,其中数字以下nn加上其数字的总和。

说明:

12345后跟12360,因为1 + 2 + 3 + 4 + 5 = 15,所以12345 + 15给出12360。类似地145后跟155。如果数字河的第一个数字,M我们将其称为河M

例如:河480是从{480,492,507,519 ....}开始的序列,河483是从{483,498,519,....}开始的序列。正常的河流和河流可以汇合,数字河流也是如此。当两条数字河流共享一些相同的值时,就会发生这种情况。

例:

河480在519与河483相遇。河480在507与河507相遇,而从不与河481相遇。每条数字河最终都会与河1,河3或河9相遇。

编写一个程序,该程序可以为给定的整数确定n河流n首先遇到这三条河流之一的值。

输入项

输入可能包含多个测试用例。每个测试用例都占一行,并包含一个整数n1 <= n <= 16384)。值为0for的测试用例将n终止输入,并且不得对该测试用例进行处理。

输出量

对于输入中的每个测试用例,首先输出测试用例编号(从1开始),如示例输出中所示。然后在单独的行输出中,行“首先在y处遇到河x”。y是河流n首先与河流相遇的最小值x(x = 1或3或9)。如果河流在处与河流n相交的值大于一个值,则输出最低值。在两个连续的测试用例之间打印空白行。xyx

测试用例

输入:

86
12345
0

输出:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

得分:

最快的算法获胜。如果是平局。较短代码的将获胜。

感谢mbomb007指出我的错误。

ps:我想拥有最快的解决方案,而不是最小的解决方案。我也有一个慢的解决方案。为此,请看这里

注意:

我将使用进行代码测试。以及性能检查。


3
我不确定您能否得分。如果某人的代码是O(log(log n))怎么办?您无法涵盖所有​​内容,因此您只需要说最快的算法获胜即可,但是如果出现平局,则最短的代码获胜,并且如果两者的长度相同,则首先发布获胜者。
mbomb007'9

3
我找不到关于旧ACM-ICPC挑战的版权或可用性的任何信息,但是可以在存档站点上找到挑战。可以在这里使用吗?
Geobits 2015年

1
这与版权无关。如有疑问,通常最简单的方法是向网站所有者发送电子邮件并询问。
Geobits 2015年

3
如果数字河的最后一位是数字,M我们将其称为河M ”是没有道理的,原因有两个:第一,如果河是无穷的数字序列,那么它就没有最后一位数字;其次,在下一段中,河流M表示从数字开始的河流M
彼得·泰勒

2
从链接的CR.SE问题来看,好像是河水是该系列中开头的任何数字,但这是最后一位数字。哪个是对的?
Celeo 2015年

Answers:


3

C,320294字节

用-std = c99编译

#include<stdio.h>
int s(int i){for(int j=i;j;j/=10)i+=j%10;return i;}int main(){int c=0,i;while(scanf("%d",&i)){c++;if(!i)continue;int j,o[]={1,3,9},p[]={1,3,9};Q:for(j=0;j<3;j++){if(o[j]==i)goto D;else if(o[j]<i){o[j]=s(o[j]);goto Q;}}i=s(i);goto Q;D:printf("Case #%d\n\nfirst meets river %d at %d\n\n",c,p[j],o[j]);}}

取消高尔夫:

#include <stdio.h>

int s(int i)
{
    for(int j = i; j; j /= 10)
        i += j % 10;
    return i;
}

int main()
{
    int c = 0, i;
    while(scanf("%d", &i))
    {
        c++;
        if(!i)
            continue;
        int j,o[]={1,3,9},p[]={1,3,9};
        Q: for(j = 0; j < 3; j++)
        {
            if(o[j] == i)
                goto D;
            else if(o[j] < i)
            {
                o[j] = s(o[j]);
                goto Q;
            }
        }
        i = s(i);
        goto Q;
        D: printf("Case #%d\n\nfirst meets river %d at %d\n\n", c, p[j], o[j]);
    }
}

试试看!

本质上,“目标”河要增加,直到它们大于我们要测试的河为止,然后再增加测试河。重复此过程,直到测试河流与其他河流相等。

我不是从该程序的命令行中读取参数,也不确定是否应该这样做。现在您可以将参数传递给STDIN。您可以通过传递非数字输入来终止。

还该死,打了半个小时。


我目前正在研究测试用例。仅3个输入测试用例将不太适合。
Kishan Kumar

请介意从stdin输入信息。
Kishan Kumar

3

JavaScript(ES6)

使用相当慢的语言,这是一个相当快的答案。确实,使用任何具有哈希表的语言执行时间都不是问题。我所有的测试都在100毫秒以下。

以测试用例列表作为输入参数的匿名方法。

F=cases=>{
  var t0 = +new Date
  var result = 0
  var spots = []
  var top=[,1,3,,9]
  var rivers=[,1,3,1,9,1,3,1]
  cases.forEach((n,i)=>{
    var found = result = spots[n]
    for (;!found;)
    {
      found = top.some((v,i)=>{
        for(;spots[v] |= i, v<n; top[i] = v)
          [...v+''].forEach(d=>v-=-d)
        return result = v-n ? 0 : i;
      }) || (
        [...n+''].forEach(d=>n-=-d),
        result = spots[n]
      )
    }  
    console.log(`Case #${i+1}\nfirst meets river ${rivers[result]} at ${n}`)
  })  
  return 'Time (ms) ' + (new Date-t0)
}  

console.log(F([86, 12345, 123, 456, 789, 16384]))


1

Java 7中,519个 505字节

import java.util.*;String c(int i){if(i<=0)return"";ArrayList<Long>r=f(1),s=f(3),t=f(9),x=f(i);String z="first meets river ";for(int j=0;j<r.size();j++){long u=r.get(j),v=s.get(j),w=t.get(j);if(x.contains(u))return z+1+" at "+u;if(x.contains(v))return z+3+" at "+v;if(x.contains(w))return z+9+" at "+w;}return"";}ArrayList f(long i){ArrayList<Long>l=new ArrayList();l.add(i);for(long j=0,x;j<9e4;j++){x=l.get(l.size()-1);for(char c:(x+"").toCharArray())x+=new Long(c+"");l.add(x);if(x>16383)return l;}return l;}

是的,它很长,很丑陋,毫无疑问可以完全更改为更多代码。.我既分心又累了,所以也许我应该再次删除它。.
老实说,这是一个非常艰巨的挑战。 。但是,至少您有第一个答案。;;)(这甚至可能比原始的非高尔夫C ++程序还要长。.xD)

非高尔夫球和测试用例:

在这里尝试。

import java.util.*;
class M{
  static String c(int i){
    if(i <= 0){
      return "";
    }
    ArrayList<Long> r = f(1),
                    s = f(3),
                    t = f(9),
                    x = f(i);
    String z = "first meets river ",
           y = " at ";
    for(int j = 0; j < r.size(); j++){
      long u = r.get(j),
           v = s.get(j),
           w = t.get(j);
      if(x.contains(u)){
        return z+1+y+u;
      }
      if(x.contains(v)){
        return z+3+y+v;
      }
      if(x.contains(w)){
        return z+9+y+w;
      }
    }
    return "";
  }

  static ArrayList f(long i){
    ArrayList<Long> l = new ArrayList();
    l.add(i);
    for(long j = 0, x; j < 9e4; j++){
      x = l.get(l.size() - 1);
      for(char c : (x + "").toCharArray()){
        x += new Long(c+"");
      }
      l.add(x);
      if(x > 16383){
        return l;
      }
    }
    return l;
  }

  public static void main(String[] a){
    System.out.println(c(86));
    System.out.println(c(12345));
    System.out.println(c(0));
  }
}

输出:

first meets river 1 at 101
first meets river 3 at 12423
(empty output)

我将把您的程序与我的程序进行比较。我也将发布我的解决方案。为什么要使用慢语言。使用任何快速的语言。
Kishan Kumar

我只注意到最快的算法标签以后..我总是在这里发布的Java 7的代码高尔夫答案..它defintely不会去赢得任何最短或最快,但..顺便说一句,你rextester给出错误时,它应该只给予警告由于缺乏铸件/型初始化。它适用于ideone(和在Eclipse IDE)。
凯文·克鲁伊森

好。让我看看。rextester给出了编译时间和执行时间。所以我用了它
Kishan Kumar

那么这就是一个问题。我将寻找其他给出编译时间和执行时间的在线编译器
Kishan Kumar

@KishanKumar我已经在我的代码中添加了强制类型转换,这应该不会影响时间afaik这是正常的rextester代码,其结果是:Compilation time: 0.62 sec, absolute running time: 0.14 sec, cpu time: 0.11 sec, memory peak: 22 Mb, absolute service time: 0,77 sec对我来说本地。所以,是的,这非常慢
。–

1

Scala,774字节

小提琴:http : //scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b

我不想打高尔夫球。在50ms内找到解决问题的方法

用法可能不完全是您想要的:

scala river.scala

现在,您可以连续输入数字,然后按Enter。并用0终止程序。按Enter键后,结果将立即打印出来。

io.Source.stdin.getLines.map(_.toInt)
  .takeWhile(_ != 0)
  .map(stream(_).takeWhile(_ < 16383))
  .zipWithIndex
  .map { cur =>
    Seq(1, 3, 9).map { i =>
      val s = stream(i).takeWhile(_ < 16383)
      (cur._2+1, i, s.intersect(cur._1).headOption)
    }
  }.foreach { opts =>
    val options = opts.filterNot(_._3.isEmpty)

    if(options.isEmpty) {
      println("No result")
    } else {
      val opt = options(0)
      println(s"Case #${opt._1}\n\nfirst meets ${opt._2} at ${opt._3.get}\n\n")
    }
  }

def stream(i:Int): Stream[Int] = {
  def sub: Int => Stream[Int] = {
    i => i #:: sub(a(i))
  }
  sub(i)
}

def a(i:Int): Int = i + i.toString.map{_.asDigit}.sum

我对Scala不太了解。因此,请您根据rextester.com/l/scala_online_compiler
Kishan Kumar

我试图将其放入其中,但在编译时超时。
AmazingDreams

好的@AmazingDreams
Kishan Kumar

@KishanKumar甚至默认值超时一次,因此该站点似乎因Scala而被破坏
AmazingDreams

@KisthanKumar使用此scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b它不支持stdin,因此我不得不更改一些小事情。
AmazingDreams

1

C,228个283 300字节

这是Yakov代码的一种改进形式,可以利用河流模式。这使其速度提高了约3倍。同样,无符号整数避免了cltod在64位计算机上的损失,因此它长了几个字节,但速度略有提高。

#define sum(z) for(y=z;y;y/=10)z+=y%10;
n,x;main(){unsigned i,j,y;while(scanf("%d",&i)){if(i){j=x=1+!(i%3)*2+!(i%9)*6;do{while(j<i)sum(j)}while(j^i&&({sum(i)i;}));printf("Case #%u\n\nfirst meets river %u at %u\n\n",++n,x,i);}}}

取消高尔夫:

#define sum(z) for(y=z;y;y/=10)z+=y%10;
n, x;
main() {
    unsigned i, j, y;
    while(scanf("%d", &i)) {
        if(i){
            j = x = 1 + !(i%3)*2 + !(i%9)*6;
            do{
                while (j < i) sum(j)
            }
            while(j^i&&({sum(i)i;}));
            printf("Case #%u\n\nfirst meets river %u at %u\n\n", ++n, x, i);
        }
    }
}

说明:

j = x = 1 + !(i%3)*2 + !(i%9)*6;

这将选择正确的河流。第1条河流与其他每条河流相遇,因此我们将此作为后备案例。如果3是测试河的最大公约数,则选择河3(1 + !(i%3)*2)。如果9是测试河的最大公约数,我们将覆盖先前的值并选择河9。

为什么这样做?河流9到达9、18、27、36等。每次以9的倍数递增,因此它将始终是通往姊妹河的最短路线。河3每次将以3的倍数递增:3、6、12、15、21等。虽然9的倍数的河流也是 3的倍数,但我们首先选择它们作为9号河,仅保留3的倍数,其余部分将首先遇到河1:1、2、4、8、16、23、28等。

选择了正确的河流后,我们将逐步踩踏两条河流,直到它们汇合为止。


1

Python 3,144个字节

r,a,b,c,i={int(input())},{1},{3},{9},1
while i:
  for x in r,a,b,c:t=max(x);x|={sum(int(c)for c in str(t))+t}
  if r&(a|b|c):i=print(*r&(a|b|c))

0

C

很简单,它看起来很长,因为我展开了所有3条河流。它首先生成最多3条河流RIVER_LENGTH(我希望这足够大),然后针对每个步骤N对所有3条河流进行二进制搜索以查看是否在其中3条河流中。之所以可行,是因为流已经排序,因此我们可以及时进行包含检查log(n)

#include <stdio.h>

#define RIVER_LENGTH 10000

int main() {
    int num_cases;
    scanf("%d", &num_cases);
    int cases[num_cases];
    int N;
    int s1[RIVER_LENGTH] = {1};
    int s3[RIVER_LENGTH] = {3};
    int s9[RIVER_LENGTH] = {9};
    int i;
    int temp;

    for (i = 1; i < RIVER_LENGTH; i++) {
        s1[i] = temp = s1[i-1];
        while (temp) {
            s1[i] += temp % 10;
            temp /= 10;
        }
    }

    for (i = 1; i < RIVER_LENGTH; i++) {
        s3[i] = temp = s3[i-1];
        while (temp) {
            s3[i] += temp % 10;
            temp /= 10;
        }
    }

    for (i = 1; i < RIVER_LENGTH; i++) {
        s9[i] = temp = s9[i-1];
        while (temp) {
            s9[i] += temp % 10;
            temp /= 10;
        }
    }

    int start;
    int end;
    int pivot;

    for (i=1; i <= num_cases; i++) {
        scanf("%d", &cases[i]);
    }

    for (i=1; i <= num_cases; i++) {
        printf("Case #%d\n\n", i);
        N = cases[i];

        while (1) {

            temp = N;
            while (temp) {
                N += temp % 10;
                temp /= 10;
            }

            start = 0;
            end = RIVER_LENGTH;
            pivot = 1;

            while (end != start && pivot != RIVER_LENGTH - 1) {
                pivot = start + ((end - start) >> 1);
                if (s1[pivot] == N) {
                    printf("first meets river 1 at %d\n\n", N);
                    goto case_done;
                } else if (N < s1[pivot]){
                    end = pivot;
                } else {
                    start = pivot+1;
                }
            }

            start = 0;
            end = RIVER_LENGTH;
            pivot = 1;

            while (end != start && pivot != RIVER_LENGTH - 1) {
                pivot = start + ((end - start) >> 1);
                if (s3[pivot] == N) {
                    printf("first meets river 3 at %d\n\n", N);
                    goto case_done;
                } else if (N < s3[pivot]){
                    end = pivot;
                } else {
                    start = pivot+1;
                }
            }

            start = 0;
            end = RIVER_LENGTH;
            pivot = 1;

            while (end != start && pivot != RIVER_LENGTH - 1) {
                pivot = start + ((end - start) >> 1);
                if (s9[pivot] == N) {
                    printf("first meets river 9 at %d\n\n", N);
                    goto case_done;
                } else if (N < s9[pivot]){
                    end = pivot;
                } else {
                    start = pivot+1;
                }
            }
        }

        case_done:;

    }
}

它首先需要一个数字来表示情况,而不是0用来分隔输入的结尾,因为您知道C。这只是为了方便起见,并没有真正影响任何东西,因此我希望它可以。


该程序在输入86,12345,0上达到了ideone上的时间限制
Kishan Kumar

ideone.com/mHCeef这里是链接。并给出了妊娠期的杀伤信号输出
Kishan Kumar

@KishanKumar首先需要一个数字表示案件数量,而不是使用0来分隔输入的结尾,因为您知道C。这只是为了方便起见,并没有真正影响任何事情,因此我希望它可以。
Maltysen '16

@KishanKumar改为尝试以下一种方法:rextester.com/XRJK89444
Maltysen

没关系。没问题。但是我将不得不为您的程序编写一个额外的脚本。因为我必须考虑所有输入范围的平均时间。
Kishan Kumar
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.