แม่น้ำดิจิตอล (ทางออกที่สั้นและเร็วที่สุด)


9

นี่เป็นคำถามแรกของฉันดังนั้นฉันหวังว่ามันจะเป็นไปด้วยดี

พื้นหลัง:

ไม่ใช่แม่น้ำที่คุณอาจคิดถึง คำถามหมุนรอบแนวคิดของแม่น้ำดิจิทัล แม่น้ำดิจิทัลเป็นลำดับของตัวเลขโดยที่จำนวนดังต่อไปnนี้nบวกกับผลรวมของตัวเลข

คำอธิบาย:

12345 ตามด้วย 12360 ตั้งแต่ 1 + 2 + 3 + 4 + 5 = 15 และอื่น ๆ 12345 + 15 ให้ 12360. ในทำนองเดียวกัน 145 ตามด้วย 155 ถ้าจำนวนแรกของแม่น้ำดิจิตอลเราจะเรียกมันว่าแม่น้ำMM

ตัวอย่างเช่น: แม่น้ำ 480 เป็นจุดเริ่มต้นของลำดับ {480,492,507,519 .... } และแม่น้ำ 483 เป็นลำดับเริ่มต้น {483,498,519, .... } ลำธารและแม่น้ำปกติสามารถพบกันและสิ่งนี้เป็นจริงสำหรับแม่น้ำดิจิตอล สิ่งนี้จะเกิดขึ้นเมื่อแม่น้ำดิจิตอลสองแห่งแบ่งปันค่าเดียวกันบางค่า

ตัวอย่าง:

แม่น้ำ 480 พบแม่น้ำ 483 ที่ 519 แม่น้ำ 480 พบแม่น้ำ 507 ที่ 507 และไม่เคยพบแม่น้ำ 481 แม่น้ำดิจิตอลทุกแม่น้ำจะพบแม่น้ำ 1 แม่น้ำ 3 หรือแม่น้ำ 9

เขียนโปรแกรมที่สามารถกำหนดจำนวนเต็มที่กำหนดให้nค่าที่แม่น้ำnตรงกับหนึ่งในสามแม่น้ำเหล่านี้ก่อน

อินพุต

อินพุตอาจมีหลายกรณีทดสอบ แต่ละกรณีทดสอบใช้สายแยกต่างหากและมีจำนวนเต็มn( 1 <= n <= 16384) กรณีทดสอบที่มีค่าเท่ากับ0สำหรับnยุติอินพุตและกรณีทดสอบนี้จะต้องไม่ถูกประมวลผล

เอาท์พุต

สำหรับแต่ละกรณีทดสอบในอินพุทเอาท์พุทครั้งแรกหมายเลขกรณีทดสอบ (เริ่มจาก 1) ดังที่แสดงในตัวอย่างผลลัพธ์ จากนั้นในบรรทัดแยกเอาต์พุตบรรทัด "แรกพบแม่น้ำ x ที่ y" นี่คือค่าต่ำสุดที่แม่น้ำnแรกพบแม่น้ำx(x = 1 หรือ 3 หรือ 9) หากแม่น้ำnตรงตามแม่น้ำxที่yคุ้มค่ามากกว่าหนึ่งของxการส่งออกมีมูลค่าต่ำสุด พิมพ์บรรทัดว่างระหว่างสองกรณีทดสอบติดต่อกัน

กรณีทดสอบ

การป้อนข้อมูล:

86
12345
0

เอาท์พุท:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

เกณฑ์การให้คะแนน:

อัลกอริทึมที่เร็วที่สุดชนะ ในกรณีที่เสมอกัน รหัสที่สั้นกว่าจะชนะ

ขอบคุณmbomb007 ที่ชี้ให้เห็นข้อผิดพลาดของฉัน

ป.ล. : ฉันต้องการมีทางออกที่เร็วที่สุดมากกว่าทางออกที่เล็กที่สุด ฉันยังมีทางออกของฉันซึ่งช้า สำหรับรูปลักษณ์ที่นี่

บันทึก:

ฉันจะใช้สิ่งนี้ในการทดสอบรหัส และการตรวจสอบประสิทธิภาพ


3
ฉันไม่แน่ใจว่าคุณจะได้คะแนนด้วยวิธีนี้ ถ้ารหัสของใครบางคนคือ O (log (log n)) คุณไม่สามารถครอบคลุมได้ทั้งหมดดังนั้นคุณต้องบอกว่าอัลกอริทึมที่เร็วที่สุดชนะ แต่ในกรณีที่เสมอกันการชนะโค้ดที่สั้นที่สุดและการชนะครั้งแรกที่โพสต์ในกรณีที่ทั้งสองมีความยาวเท่ากัน
mbomb007

3
ฉันไม่พบสิ่งใดเกี่ยวกับลิขสิทธิ์หรือการใช้งานของความท้าทาย ACM-ICPC แบบเก่า แต่ฉันสามารถค้นหาความท้าทายนี้ได้ในไซต์เก็บถาวร อนุญาตให้ใช้ที่นี่ได้ไหม
Geobits

1
เรื่องนี้ไม่มีส่วนเกี่ยวข้องกับลิขสิทธิ์ หากมีข้อสงสัยสิ่งที่ง่ายที่สุดคือการส่งอีเมลถึงเจ้าของไซต์และถาม
Geobits

3
" ถ้าเลขตัวสุดท้ายของแม่น้ำดิจิทัลคือMเราจะเรียกมันว่าแม่น้ำM " ไม่สมเหตุสมผลด้วยสองเหตุผล: ประการแรกถ้าแม่น้ำเป็นลำดับที่ไม่มีที่สิ้นสุดของตัวเลขก็จะไม่มีหลักสุดท้าย และประการที่สองในย่อหน้าถัดไปแม่น้ำMMหมายถึงแม่น้ำเริ่มต้นที่บ้านเลขที่
Peter Taylor

2
จากคำถาม CR.SE ที่เชื่อมโยงดูเหมือนว่าแม่น้ำเป็นหมายเลขใดที่ขึ้นต้นด้วยในซีรีส์ แต่นี่คือหลักสุดท้าย อันไหนถูกต้อง?
Celeo

คำตอบ:


3

C, 320 294ไบต์

คอมไพล์ด้วย -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]);}}

Ungolfed:

#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;}

ใช่มันยาวน่าเกลียดและไม่ต้องสงสัยเลยว่าจะเปลี่ยนเป็น code-golf อย่างสมบูรณ์มากขึ้น .. ฉันทั้งฟุ้งซ่านและเหนื่อยล้าดังนั้นบางทีฉันควรจะลบมันอีกครั้ง
มันเป็นความท้าทายที่ค่อนข้างยากที่จะซื่อสัตย์ . แต่อย่างน้อยคุณก็มีคำตอบแรก .. ;) (ซึ่งอาจจะนานกว่าโปรแกรม C ++ ดั้งเดิมของคุณที่ xg)

กรณีที่ไม่ได้รับการทดสอบ &:

ลองที่นี่

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 กอล์ฟเสมอที่นี่ .. มันจะไม่ชนะอย่างใดอย่างหนึ่งไม่ว่าจะสั้นหรือเร็วที่สุด .. Btw, rextesterของคุณให้ข้อผิดพลาด สำหรับการขาด casts / type-initializes .. มันทำงานบนideone (และใน Eclipse IDE)
Kevin Cruijssen

ตกลง. ให้ฉันดู. 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สำหรับฉันในพื้นที่ ใช่แล้วมันค่อนข้างช้า ..
Kevin Cruijssen

1

สกาลา, 774 ไบต์

ซอ: http://scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b

ฉันไม่รู้สึกอยากเล่นกอล์ฟ ค้นหาวิธีแก้ไขปัญหาที่โพสต์ภายใน 50ms

การใช้งานอาจไม่ตรงตามที่คุณต้องการ:

scala river.scala

ตอนนี้คุณสามารถป้อนหมายเลขอย่างต่อเนื่องตามด้วยการป้อน และยุติโปรแกรมด้วย 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

ฉันไม่ค่อยรู้เรื่องสกาล่ามากนัก ดังนั้นคุณสามารถแก้ไขรหัสซึ่งจะเป็นไปตามrextester.com/l/scala_online_compiler
Kishan Kumar

ฉันพยายามที่จะใส่ไว้ในนั้น แต่มันหมดเวลาในขณะที่รวบรวม
AmazingDreams

ok @AmazingDreams
Kishan Kumar

@KishanKumar แม้แต่ค่าเริ่มต้นหนึ่งครั้งดังนั้นเว็บไซต์ดูเหมือนว่าจะถูกแบ่งให้เป็นที่น่า
กลัว

@KisthanKumar ใช้สิ่งนี้scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209bมันไม่รองรับ stdin แต่ฉันต้องเปลี่ยนบางสิ่งเล็กน้อย
AmazingDreams

1

C, 228 283 300ไบต์

นี่เป็นรหัสของยาโคฟเพื่อใช้ประโยชน์จากรูปแบบแม่น้ำ มันทำให้เร็วขึ้น ~ 3x นอกจากนี้จำนวนเต็มที่ไม่ได้ลงชื่อจะหลีกเลี่ยงการถูก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);}}}

Ungolfed:

#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

ง่ายมากมันดูยาวมากเพราะฉันเปิดโปงแม่น้ำทั้งสามสาย มันสร้างแม่น้ำสามสายขึ้นไปRIVER_LENGTH(ซึ่งฉันหวังว่าจะใหญ่พอ) จากนั้นสำหรับแต่ละขั้นตอนNมันจะทำการค้นหาแบบไบนารีบนลำธารทั้งสามเพื่อดูว่ามีอยู่ในนั้นหรือไม่ ใช้งานได้เนื่องจากสตรีมเรียงลำดับแล้วดังนั้นเราจึงสามารถทำเวลาเช็คอิน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 นี่เป็นเพียงเพื่อความสะดวกและไม่ส่งผลกระทบอะไรเลยจริง ๆ ดังนั้นฉันหวังว่ามันจะไม่เป็นไร


โปรแกรมนี้มีการ จำกัด เวลาสำหรับ ideone เกินจำนวนอินพุต 86,12345,0
Kishan Kumar

ideone.com/mHCeefนี่คือลิงค์ และจะให้สัญญาณฆ่าเมื่อ rextester
Kishan Kumar

@ KishanKumar ใช้ตัวเลขสำหรับจำนวนคดีก่อนแทนที่จะใช้ 0 เพื่อกำหนดจุดสิ้นสุดของอินพุตเนื่องจากคุณรู้ C นี่เป็นเพียงเพื่อความสะดวกและไม่ส่งผลกระทบอะไรเลย
Maltysen

@KishanKumar ลองใช้สิ่งนี้แทน: rextester.com/XRJK89444
Maltysen

ไม่เป็นไร. ไม่มีปัญหา. แต่ฉันจะต้องเขียนสคริปต์พิเศษสำหรับโปรแกรมของคุณ เพราะฉันต้องใช้เวลาเฉลี่ยของช่วงอินพุตทั้งหมด
Kishan Kumar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.