Dependencias triangulares


25

Un número triangular es un número que es la suma de nnúmeros naturales del 1 al n. Por ejemplo, 1 + 2 + 3 + 4 = 10así 10es un número triangular.

Dado un entero positivo ( 0 < n <= 10000) como entrada (puede tomarse como un entero o como una cadena), devuelve el número triangular más pequeño posible que se puede agregar a la entrada para crear otro número triangular.

Por ejemplo 26, entrada dada , agregando 10resultados en 36, que también es un número triangular. No hay números triangulares más pequeños 10que se puedan agregar para 26crear otro número triangular, por lo que 10es el resultado correcto en este caso.

0 es un número triangular, por lo tanto, si la entrada es en sí misma un número triangular, la salida debería ser 0

Casos de prueba

Los casos se dan en el formato input -> output (resulting triangular number)

0     -> 0   (0)
4     -> 6   (10)
5     -> 1   (6)
7     -> 3   (10)
8     -> 28  (36)
10    -> 0   (10)
24    -> 21  (45)
25    -> 3   (28)
26    -> 10  (36)
34    -> 21  (55)
10000 -> 153 (10153)

Tanteo

Este es el por lo que gana menos bytes en cada idioma .


¿No es así 26 -> 2?
Okx

@Okx Cometí el mismo error, necesitas encontrar un número triangular para agregarlo al actual y hacer otro número triangular.
Martin Ender

2
Relacionado. (duplicado límite)
Martin Ender

Respuestas:


21

Java 8, 58 57 bytes

n->{int i=0,m=0;while(n!=0)n+=n<0?++i:--m;return-~i*i/2;}

Conjunto de pruebas en línea

Gracias a Dennis por un ahorro de 1 byte.


66
¡Ahora esto es Java, golfizado! :)
Olivier Grégoire

44
@Computronium, el orden de las operaciones está garantizado por la Especificación del lenguaje Java . Java evita deliberadamente algunas de las debilidades de C.
Peter Taylor


2
return-~i*i/2;guarda un byte.
Dennis

1
@Okx Java es paso por valor para los tipos primitivos y paso por referencia para los objetos (incluidas las matrices). Si realmente desea generar la misma variable, debe estar en un contexto de paso por referencia (dicho explícitamente en su enlace). La única forma en que veo pasar por referencia que podría funcionar es pasar un argumento en int[]lugar de uno int. Pero eso significa tratar con matrices más adelante. Esto podría funcionar: x->{int i=0,m=0,n=x[0];while(n!=0)n+=n<0?++i:--m;x[0]=-~i*i/2;}pero son 63 bytes.
Olivier Grégoire

7

MATL , 13 12 bytes

1 byte eliminado usando una idea (establecer intersección) de la respuesta 05AB1E de Emigna

Q:qYstG-X&X<

Pruébalo en línea!

Explicación

Deje t(n) = 1 + 2 + ··· + ndenotar el nenésimo número triangular.

El código explota el hecho de que, dada n, la solución está limitada por t(n-1). Para ver esto, observe que t(n-1) + nes igual t(n)y entonces es un número triangular.

Considere la entrada 8como un ejemplo.

Q:q   % Input n implicitly. Push [0 1 2 ... n]
      % STACK: [0 1 2 3 4 5 6 7 8]
Ys    % Cumulative sum
      % STACK: [0 1 3 6 10 15 21 28 36]
t     % Duplicate
      % STACK: [0 1 3 6 10 15 21 28 36], [0 1 3 6 10 15 21 28 36]
G-    % Subtract input, element-wise
      % STACK: [0 1 3 6 10 15 21 28 36], [-8 -7 -5 -2  2  7 13 20 28]
X&    % Set intersection
      % STACK: 28
X<    % Minimum of array (in case there are several solutions). Implicit display
      % STACK: 28

¿Puedes eliminar la guía Qcon tu argumento sobre la limitación?
Giuseppe

@Giuseppe No, eso falla para la entrada 8. Cuando la salida es igual al límite t(n-1), el código lo obtiene como t(n)-n. Entonces t(n)es necesario. Gracias por la idea de todos modos!
Luis Mendo

7

Java (OpenJDK 8) , 83 bytes

n->{int m=0,a=n,b;for(;a-->0;)for(b=0;b<=n;)m=2*n+b*~b++==a*~a?a*a+a:m;return m/2;}

Pruébalo en línea!

Créditos


1
Buena respuesta (como siempre ..). No había notado que ya había una respuesta de Java cuando publiqué la mía . La mía fue inicialmente más corta, pero ya no parece. :)
Kevin Cruijssen

¡Gracias! Sí, mi primera respuesta fue realmente redundante. Lo arreglé y lo hice más complicado, aunque también más codicioso de procesador. ¡Veré el tuyo en un segundo!
Olivier Grégoire

Todavía no entiendo lo que está pasando aquí. ¿Por qué está funcionando? Estás reemplazando m cada vez, entonces, ¿cuál es el punto?
V. Courtois

2
@ V.Courtois La pregunta pide la más pequeña m. Entonces voy de aabajo a 0. "pero usted está asignando tal vez 100 veces el mismo valor a*a+aque men el b-loop", sí, yo no necesito hacerlo 100 veces, pero estoy ganando bytes por no romper el b-loop anterior.
Olivier Grégoire

Veo @ OlivierGrégoire. Entonces, eso es antieficiente a propósito: D
V. Courtois

5

Mathematica, 46 bytes

Min[Select[(d=Divisors[2#])-2#/d,OddQ]^2-1]/8&

4

Neim , 12 9 bytes

tS𝕊Λt𝕚)0𝕔

Esto toma demasiado tiempo para computar (pero funciona dado un tiempo y memoria infinitos), por lo que en el enlace solo genero los primeros 143 números triangulares, usando £𝕖, que es suficiente para manejar una entrada de 10,000, pero no lo suficiente como para agotar el tiempo de espera.

Advertencia: esto puede no funcionar en futuras versiones. Si es así, sustituya £ por 143

Explicación:

t                 Infinite list of triangular numbers
 [ 𝕖]             Select the first  v  numbers
 [£ ]                              143
     S𝕊           Subtract the input from each element
       Λ  )       Only keep elements that are
        t𝕚          triangular
           0𝕔     Get the value closest to 0 - prioritising the higher number if tie

¡Intentalo!


¿Cómo son los primeros 143 números triangulares suficientes para cualquier entrada entre 0 y 10000? Con la entrada 9998, el resultado esperado es 3118753, que está muy por encima del número 143 del triángulo (que es `10296).
Olivier Grégoire

@ OlivierGrégoire porqueThis takes too long to compute (but works given infinite time and memory)
Stephen

Gracias @StepHen pero eso no es lo que dije. Lo que implicaba es que la oración "los primeros 143 números triangulares [son] suficientes para manejar una entrada de 10,000" está equivocada. No he hecho los cálculos, pero creo que deberías necesitar alrededor de 10000 números de triángulo (más o menos) para manejar los casos hasta 10000.
Olivier Grégoire

@ OlivierGrégoire Dije que es suficiente para manejar una entrada de 10,000, pero no un número menor. Siéntase libre de cambiar £a un número más alto, como 200.
Okx

@ Ok Ok, no lo entendí así cuando leí por primera vez, gracias por tomarse el tiempo para explicar :)
Olivier Grégoire

4

PHP , 45 bytes

for(;!$$t;$t+=++$i)${$argn+$t}=~+$t;echo~$$t;

Pruébalo en línea!

Es la variante más corta de for(;!$r[$t];$t+=++$i)$r[$argn+$t]=~+$t;echo~$r[$t];

Expandido

for(;!$$t;  # stop if a triangular number exists where input plus triangular number is a triangular number
$t+=++$i) # make the next triangular number
  ${$argn+$t}=~+$t; # build variable $4,$5,$7,$10,... for input 4 
echo~$$t; # Output result 

PHP , 53 bytes

for(;$d=$t<=>$n+$argn;)~$d?$n+=++$k:$t+=++$i;echo+$n;

Pruébalo en línea!

Use el nuevo operador de nave espacial en PHP 7

Expandido

for(;$d=$t<=>$n+$argn;) # stop if triangular number is equal to input plus triangular number 
  ~$d
    ?$n+=++$k  # raise additional triangular number
    :$t+=++$i; # raise triangular number sum
echo+$n; # Output and cast variable to integer in case of zero

PHP , 55 bytes

for(;fmod(sqrt(8*($t+$argn)+1),2)!=1;)$t+=++$i;echo+$t;

Pruébalo en línea!


4

Java 8, 110 102 100 93 92 bytes

n->{int r=0;for(;t(r)<-t(n+r);r++);return r;}int t(int n){for(int j=0;n>0;n-=++j);return n;}

-2 bytes gracias a @PeterTaylor .
-7 bytes gracias a @JollyJoker .
-1 byte gracias a @ceilingcat .

Explicación:

Pruébalo en línea.

n->{                  // Method with integer as parameter and return-type
  int r=0;            //  Result-integer (starting at 0)
  for(;t(r)<-t(n+r);  //  Loop as long as neither `r` nor `n+r` is a triangular number
    r++);             //   And increase `r` by 1 after every iteration
  return r;}          //  Return the result of the loop

int t(int n){         // Separate method with integer as parameter and return-type
                      // This method will return 0 if the input is a triangular number
  for(int i=0;n>0;)   //  Loop as long as the input `n` is larger than 0
    n-=++j;           //   Decrease `n` by `j` every iteration, after we've raised `j` by 1
  return n;}          //  Return `n`, which is now either 0 or below 0

1
Más fácil de leer de las soluciones de Java :)
jollyjoker

@JollyJoker Quizás es por eso que es el más largo. ;) ¿O es por mi explicación adicional?
Kevin Cruijssen

No, estaba pensando en el código. Probablemente pasé 15 minutos descubriendo cómo funciona la solución de Peter Taylor. El tuyo es claro incluso sin los comentarios.
JollyJoker

3

Brachylog , 17 15 bytes

⟦{a₀+}ᶠ⊇Ċ-ṅ?∧Ċh

Pruébalo en línea!

Explicación

⟦                  [0, …, Input]
 {   }ᶠ            Find all…
  a₀+                …Sums of prefixes (i.e. triangular numbers)
       ⊇Ċ          Take an ordered subset of two elements
         -ṅ?       Subtracting those elements results in -(Input)
            ∧Ċh    Output is the first element of that subset

3

Python 2 , 59 bytes

lambda n:min((r-2*n/r)**2/8for r in range(1,2*n,2)if n%r<1)

Pruébalo en línea!

Utiliza la siguiente caracterización de los números triangulares tque se pueden agregar npara obtener un número triangular:

8*t+1 = (r-2*s)^2para pares divisores (r,s)con r*s==ny rimpar.

El código toma el mínimo de todos esos números triangulares.


3

Jalea , 8 bytes

0r+\ðf_Ḣ

Pruébalo en línea!

Cómo funciona

0r+\ðf_Ḣ  Main link. Argument: n

0r        Build [0, ..., n].
  +\      Take the cumulative sum, generating A := [T(0), ..., T(n)].
    ð     Begin a dyadic chain with left argument A and right argument n.
      _   Compute A - n, i.e., subtract n from each number in A.
     f    Filter; keep only numbers of A that appear in A - n.
       Ḣ  Head; take the first result.

3

Japt , 24 23 16 15 bytes

ò å+
m!nNg)æ!øU

Pruébalo

1 byte guardado gracias a ETH


Explicación

    :Implicit input of integer U.
ò   :Create an array of integers from 0 to U, inclusive.
å+  :Cumulatively reduce by summing. Result is implicitly assigned to variable V.
m   :Map over U.
!n  :From the current element subtract...
Ng  :  The first element in the array of inputs (the original value of U).
æ   :Get the first element that returns true when...
!øU :  Checking if U contains it.
    :Implicit output of resulting integer.

Creo que puedes guardar un byte con æ!øV. Aparte de eso, se ve muy bien :-)
ETHproductions



2

Mathematica, 62 bytes

(s=Min@Abs[m/.Solve[2#==(n-m)(n+m+1),{n,m},Integers]])(s+1)/2&

No conozco Mathematica, pero sería Solve[2*#==m(m+1)-n(n+1)más corto (si funciona).
Kritixi Lithos

Sí, acabo de publicar mi respuesta y estoy tratando de jugar golf ahora mismo
J42161217

2

Python 2 , 78 71 70 bytes

Siete bytes guardados, gracias a los ovs y theespinosa

Un byte más salvado debido a la observación de Neil , x+9es suffisant y comprobado para todos los números naturales 0 <= n <= 10000. También se verificó para en x+1lugar de x+9, funciona también.

x=input()
I={n*-~n/2for n in range(x+1)}
print min(I&{i-x for i in I})

Pruébalo en línea!


2
Puede usar en n*-~n/2lugar den*(n+1)/2
2017

2
¿El rango (x + 9) funcionaría?
Neil

2
Puede usar en {n*(n+1)/2for n in range(999)}lugar de explícito sety también usar en {}lugar de seten la tercera línea
TheEspinosa

2

JavaScript (ES6), 43 42 bytes

f=(n,a=s=0)=>n?f(n+=n>0?--s:++a,a):a*++a/2
<input type=number min=0 value=0 oninput=o.textContent=f(+this.value)><pre id=o>0

Editar: guardado 1 byte gracias a @PeterTaylor.


Establecer una variable global es un abuso horrible de un parámetro predeterminado. +1. Pero FWIW puede guardar un byte adicional reemplazándolo -++scon --s, como hice en mi versión Java derivada de forma independiente pero bastante similar. (Anexo: también debe cambiar la prueba a n>0).
Peter Taylor

@PeterTaylor Huh, ¡así que el n>scheque fue un arenque rojo todo el tiempo!
Neil

No funciona para 8192
Jörg Hülsermann

@ JörgHülsermann Si te refieres al fragmento, entonces el tamaño de la pila de tu navegador puede no ser lo suficientemente grande, o puede que necesites un navegador con optimización experimental de la cola de llamadas. Alternativamente, si está utilizando NodeJS para probar, use node --stack_size=para aumentar su tamaño de pila.
Neil

2

Python 3 , 60 44 bytes

f=lambda n,k=1:(8*n+1)**.5%1and f(n+k,k+1)+k

¡Gracias a @xnor por una sugerencia que ahorró 16 bytes!

Pruébalo en línea!

Fondo

Sea n un número entero no negativo. Si n es el k número triangular, tenemos

condición

lo que significa que habrá una solución natural si y solo si 1 + 8n es un cuadrado extraño y perfecto. Claramente, no se requiere verificar la paridad de 1 + 8n .

Cómo funciona

La función recursiva n acepta un único entero no negativo como argumento. Cuando se llama con un solo argumento, k se establece de manera predeterminada en 1 .

Primero, (8*n+1)**.5%1comprueba si n es un número triangular: si (y solo si) lo es, (8*n+1)**.5producirá un número entero, por lo que el residuo de la división por 1 producirá 0 .

Si el módulo es 0 , la andcondición fallará, haciendo que f regrese 0 . Si esto sucede en la llamada inicial a f , tenga en cuenta que esta es la salida correcta ya que n ya es triangular.

Si el módulo es positivo, la andcondición se mantiene y f(n+k,k+1)+kse ejecuta. Esto llama a f nuevamente, incrementando n por k y k por 1 , luego agrega k al resultado.

Cuando f (n 0 , k 0 ) finalmente devuelve 0 , retrocedemos de la recursión. El primer argumento en la primera llamada fue n , el segundo n + 1 , el tercero n + 1 + 2 , hasta que finalmente n 0 = n + 1 + ... k 0 -1 . Tenga en cuenta que n 0 - n es un número triangular.

Del mismo modo, todos estos enteros se agregarán al valor de retorno más interno ( 0 ), por lo que el resultado de la llamada inicial f (n) es n 0 - n , como se desee.


Si también incrementa el nrecursivo, puede escribir en nlugar de (n+k).
xnor


Wow, eso es mucho mejor de lo que estaba intentando.
xnor

2

C # (.NET Core) , 291 281 bytes

class p{static int Main(string[]I){string d="0",s=I[0];int c=1,j,k;for(;;){j=k=0;string[]D=d.Split(' '),S=s.Split(' ');for(;j<D.Length;j++)for(;k<S.Length;k++)if(D[j]==S[k])return int.Parse(D[k]);j=int.Parse(D[0])+c++;d=d.Insert(0,$"{j} ");s=s.Insert(0,$"{j+int.Parse(I[0])} ");}}}

Pruébalo en línea! Programa que toma una cadena como entrada y salida a través del código de salida.

Guardado 10 Bytes gracias a Kevin Cruijssen


1
Hola, bienvenido a PPCG! No necesita un programa completo a menos que el desafío indique lo contrario. El valor predeterminado es programa / función, por lo que también se permite una lambda en C #. Pero si quieres usar el programa, puedes jugar algunas cosas en tu código actual: class p{static int Main(string[]I){string d="0",s=I[0];int c=1,j,k;for(;;){j=k=0;string[]D=d.Split(' '),S=s.Split(' ');for(;j<D.Length;j++)for(;k<S.Length;k++)if(D[j]==S[k])return int.Parse(D[k]);j=int.Parse(D[0])+c++;d=d.Insert(0,$"{j} ");s=s.Insert(0,$"{j+int.Parse(I[0])} ");}}}( 281 bytes )
Kevin Cruijssen

@KevinCruijssen Gracias por el consejo! usar for(;;)para hacer un bucle infinito es un buen golpe, y me aseguraré de pensar más detenidamente si usar var es realmente más eficiente que usar un tipo explícito pero combinando las declaraciones, y supongo que será más diligente en eliminar los corchetes innecesarios. En cuanto al programa vs. función, comencé con un lambda pero no pude ejecutarlo en TIO. Sé que un enlace TIO no es realmente necesario, pero es algo que me gusta ver en las respuestas de los demás, así que quería al menos algo similar en la mía.
Kamil Drakari

Tampoco soy muy bueno en C # lambdas tbh, generalmente codegolf en Java. Pero creo que esto debería ser correcto . ( 252 bytes ). Además, en caso de que aún no lo haya visto: puede ser interesante leer los consejos para jugar golf en código en C # y los consejos para jugar golf en <todos los idiomas> . Nuevamente bienvenido, y +1 de mi parte. Buena primera respuesta. Disfruta tu estancia. :)
Kevin Cruijssen

2

JavaScript (ES7), 46 44 bytes

f=(n,x=r=0)=>(8*(n+x)+1)**.5%1?f(n,x+=++r):x

Intentalo

o.innerText=(
f=(n,x=r=0)=>(8*(n+x)+1)**.5%1?f(n,x+=++r):x
)(i.value=8);oninput=_=>o.innerText=f(+i.value)
<input id=i type=number><pre id=o>


1
Funcionaria r=x=0?
Kritixi Lithos

Lamentablemente no, @KritixiLithos.
Shaggy


1

Dyalog APL, 19 bytes

6 bytes guardados gracias a @KritixiLithos

{⊃o/⍨o∊⍨⍵+o←0,+\⍳⍵}

Pruébalo en línea!

¿Cómo?

o←0,+\⍳⍵- asigna olos primeros números triangulares

o/⍨- filtrar opor

o∊⍨⍵+o- números triangulares que se suman con producir triangulares

- y toma el primero


+\⍳⍵debería funcionar en lugar de lo que está utilizando para generar los números triangulares.
Kritixi Lithos

Creo que funciona en lugar de⌊/
Kritixi Lithos



1

Agregar ++ , 68 bytes

L,RBFEREsECAAx$pBcB_B]VARBFEREsB]GEi$pGBcB*A8*1+.5^1%!!@A!@*b]EZBF#@

Pruébalo en línea! , o ver el conjunto de pruebas !

Incluso Java me está ganando. Realmente necesito agregar algunos comandos establecidos para Agregar ++

Cómo funciona

L,    - Create a lambda function
      - Example argument:  8
  R   - Range;     STACK = [[1 2 3 4 5 6 7 8]]
  BF  - Flatten;   STACK = [1 2 3 4 5 6 7 8]
  ER  - Range;     STACK = [[1] [1 2] ... [1 2 3 4 5 6 7 8]
  Es  - Sum;       STACK = [1 3 6 10 15 21 28 36]
  EC  - Collect;   STACK = [[1 3 6 10 15 21 28 36]]
  A   - Argument;  STACK = [[1 3 6 10 15 21 28 36] 8]
  A   - Argument;  STACK = [[1 3 6 10 15 21 28 36] 8 8]
  x   - Repeat;    STACK = [[1 3 6 10 15 21 28 36] 8 [8 8 8 8 8 8 8 8]]
  $p  - Remove;    STACK = [[1 3 6 10 15 21 28 36] [8 8 8 8 8 8 8 8]]
  Bc  - Zip;       STACK = [[1 8] [3 8] [6 8] [10 8] [15 8] [21 8] [28 8] [36 8]]
  B_  - Deltas;    STACK = [-7 -5 -2 2 7 13 20 28]
  B]  - Wrap;      STACK = [[-7 -5 -2 2 7 13 20 28]]
  V   - Save;      STACK = []
  A   - Argument;  STACK = [8]
  R   - Range;     STACK = [[1 2 3 4 5 6 7 8]]
  BF  - Flatten;   STACK = [1 2 3 4 5 6 7 8]
  ER  - Range;     STACK = [[1] [1 2] ... [1 2 3 4 5 6 7 8]]
  Es  - Sum;       STACK = [1 3 6 10 15 21 28 36]
  B]  - Wrap;      STACK = [[1 3 6 10 15 21 28 36]]
  G   - Retrieve;  STACK = [[1 3 6 10 15 21 28 36] [-7 -5 -2 2 7 13 20 28]]
  Ei  - Contains;  STACK = [[1 3 6 10 15 21 28 36] [0 0 0 0 0 0 0 1]]
  $p  - Remove;    STACK = [[0 0 0 0 0 0 0 1]]
  G   - Retrieve;  STACK = [[0 0 0 0 0 0 0 1] [-7 -5 -2 2 7 13 20 28]]
  Bc  - Zip;       STACK = [[0 -7] [0 -5] [0 -2] [0 2] [0 7] [0 13] [0 20] [1 28]]
  B*  - Products;  STACK = [0 0 0 0 0 0 0 28]
  A   - Argument;  STACK = [0 0 0 0 0 0 0 28 8]
  8*  - Times 8;   STACK = [0 0 0 0 0 0 0 28 64]
  1+  - Increment; STACK = [0 0 0 0 0 0 0 28 65]
  .5^ - Root;      STACK = [0 0 0 0 0 0 0 28 8.1]
  1%  - Frac part; STACK = [0 0 0 0 0 0 0 28 0.1]
  !!  - To bool;   STACK = [0 0 0 0 0 0 0 28 1]
  @   - Reverse;   STACK = [1 28 0 0 0 0 0 0 0]
  A   - Argument;  STACK = [1 28 0 0 0 0 0 0 0 8] 
  !   - Not;       STACK = [1 28 0 0 0 0 0 0 0 0]
  @   - Reverse;   STACK = [0 0 0 0 0 0 0 0 28 1]
  *   - Multiply;  STACK = [0 0 0 0 0 0 0 0 28]
  b]  - Wrap;      STACK = [0 0 0 0 0 0 0 0 [28]]
  EZ  - Unzero;    STACK = [[28]]
  BF  - Flatten;   STACK = [28]
  #   - Sort;      STACK = [28]
  @   - Reverse;   STACK = [28]

1

R , 46 44 43 41 bytes

function(x,y=cumsum(0:x))y[(x+y)%in%y][1]

Pruébalo en línea!

Una función anónima con un argumento obligatorio x; calcula los primeros x+1números triangulares como argumento opcional para jugar golf con unas llaves. Solía chooseantes de ver la respuesta de Octava de Luis Mendo .

Afeité algunos bytes de la respuesta de Luis Mendo, pero olvidé usar la misma idea en mi respuesta.





0

Clojure, 74 bytes

#(nth(for[t[(reductions +(range))]i t :when((set(take 1e5 t))(+ i %))]i)0)
#(nth(for[R[reductions]i(R + %(range)):when((set(R - i(range 1e5)))0)]i)0)

Elige tu favorito :) Los bucles pueden ser más cortos ...


0

Python 2 , 82 bytes

f=lambda n,R=[1]:n-sum(R)and f(n,[R+[R[-1]+1],R[1:]][sum(R)>n])or sum(range(R[0]))

Pruébalo en línea

Esto fue creado modificando esta respuesta de la pregunta relacionada.


no funciona para 8192
Jörg Hülsermann

Tampoco funciona para eso en la pregunta relacionada, debido a la profundidad de recursión. No estoy seguro de cuál es el consenso al respecto.
mbomb007

Algunas otras respuestas tienen el mismo problema. Solo doy la información
Jörg Hülsermann
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.