The phraseology "don't repeat yourself" is a little oversimplistic. What's important is "avoid having one piece of potentially-changeable information encapsulated in two independent places."
If a program is supposed to process widgets, each with three woozles, and are many loops of the form
for (i=0; i<3; i++)
then the expectation that the widgets are expected to contain three woozles would be encapsulated in each of those loops, and updating the code to accommodate any other number of woozles per widget could be difficult. By contrast, if one were to say
#define WOOZLES_PER_WIDGET 3
and each loop were rewritten
for (i=0; i<WOOZLES_PER_WIDGET; i++) ...
such a design might make it very easy to change the number of woozles per widget.
It's important to note, however, that while it's desirable to consolidate information like the number of woozles per widget to a single point, it's not always practical. Sometimes it may be necessary to hard-code logic which will only be work if things are a particular size. For example, if each woozle has a value and one wants to find the median associated with a particular widget, it may be possible to sort the values and take the middle one, and such an approach would work with any number of woozles, but logic which is hand-written specifically to find the median of three items could be significantly faster.
While having a WOOZLES_PER_WIDGET constant may make code more readable, it should be commented to make clear that its value cannot be changed without making other adjustments to program logic. In that case, the logic which is hard-coded for three items and the constant WOOZLES_PER_WIDGET would both be duplicating the information "each widget has three woozles", but the benefits of such duplication (greater execution speed) could outweigh the cost.