P1008 [NOIP1998 Popularization Group] Three combos

Title background

This question is an answer question. You can write a program or calculate the answer by hand on the computer, and then submit the answer text directly, or submit the answer generation program.

Description of topic

Divide 99 numbers 1, 2, \ldots , 91,2,…,9 into 33 groups to form 33 three-digit numbers, and make these 33 three-digit numbers form 1 : 2 : 31:2:3 , try to find all 33 three-digit numbers that meet the conditions.

Input format

none

Output format

Several lines of 33 numbers each. Sort in ascending order of the 11th number in each row.

Sample input and output

Enter #1 to copy

none

Output #1 Copy

192 384 576
* * *
...

* * *
(The rest will not be displayed)

program

#include <stdio.h>
int main()
{
    int a,b,c;
    for(a=123;a<=333;a + + )
            {
                b=a*2;
                c=a*3;
                if((a/100 + a/10 + a + b/100 + b/10 + b + c/100 + c/10 + c ==1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9) & &((a/100)*(a/10)*(a)*(b/100)*(b/10)*(b) *(c/100)*(c/10)*(c)==(1)*(2)*(3)*(4)*(5)*(6)*(7)*(8 )*(9)))
                    printf("%d %d %d\\
",a,b,c);
            }
    return 0;
}

tips:/

1. Basic concepts of expressions
During operand type conversion, small integer types (bool, char, short) are usually promoted (promoted) to larger integer types (int).

The C++ language defines what operators do when they operate on operands of built-in types and composite types. When an operator acts on an operand of a class type, the user can customize its meaning. This process is called operator overloading.
The >> and << of the IO library, as well as string objects, vector objects, and iterators all use overloaded operators.
When an operator is overloaded, the type of the operand and the type of the return value can be customized, but the number of operands, operator priority and associativity cannot be changed.

When an object is used as an rvalue, the object’s content/value is used, and when an object is used as an lvalue, the object’s identity/location in memory is used. Simple induction in C cannot be used (lvalues can be on the left side of assignment statements, rvalues cannot), for the following reasons:

The formal distinction (or grammatical distinction) of lvalue and rvalue is whether the address & amp; operator can be used; the semantic distinction (that is, its essential meaning) lies in whether the expression represents a persistent object or a temporary object

In the process of operator operation, there is an important principle. Where an rvalue is needed, an lvalue can be used instead. At this time, the content of the lvalue is used, but an rvalue cannot be used where an lvalue is needed.

Parameters and return results of common operators:

Assignment operator: takes a non-const lvalue as the left operand and returns an lvalue.
Address operator: acts on an lvalue object and returns an rvalue
Built-in dereference operator, subscript operator, iterator dereference operator: evaluates to an lvalue
Increment and decrement operators for built-in types and iterators: acting on lvalues, the result is an lvalue. (Iterators can also take addresses)
The operands and evaluation results of arithmetic operators ( + , -, *, /, %) are rvalues.
When using the keyword decltype, if the expression evaluates to an lvalue, the result is a reference type:

2. The order of evaluation of expressions
Precedence specifies how the operands are combined, but does not specify in what order the operands are evaluated.
In most cases, operators do not have a clear order of evaluation. For those operators that do not have a clear order of evaluation, if multiple expressions of a statement point to and modify the same object, undefined behavior will occur. As follows, the << operator does not specify the order of evaluation:

There are four operators that clearly specify the evaluation order of the operands, namely & amp; & amp;, ||, ?:, ,

Some advice on writing compound expressions:

3. Arithmetic operators
Arithmetic operator precedence (gradually decreasing from top to bottom, the same precedence in the same column):

*, / have the same priority, follow the left associative law, and operate from left to right.
Before expression evaluation, small integer types are promoted to larger integer types, so it is best not to use bool to participate in the operation, as shown below:

Both operands of the remainder operation must be integers. as follows:

If m%n!=0, then his sign is the same as m.

4. Logical operators
Logical (and or not) and relational (remaining) operator precedence (decreasing priority from top to bottom, the same priority in the same column):

A little trick, in loop traversal, you can set the traversal tool as a reference to prevent copying. like:

All relational operators are left associative. and returns a boolean value. as follows:

When an arithmetic object or pointer object is used as a judgment condition, it will be converted into a bool value first:

But if the Bool value is involved in the operation, it will be converted to an integer value (false->0, true->1):

In other words, only when val is a bool value can bool values be used to participate in logical operations.

5. Assignment operator
Assignment operations are right-associative (operating from right to left).

Note: The returned left operand is treated as an lvalue

Assignments where the above types are different and cannot be converted are illegal.

Taking advantage of the property that the assignment statement returns the operand on the left side, you can write more concise code:

When using the above structure, pay attention to one point:

Each operator has a corresponding compound form:

6. Increment and decrement operators
There are two versions of the increment and decrement operators, the pre-version and the post-version, both act on lvalue objects, the pre-version returns the object itself as an lvalue, and the post-version returns a copy of the object as an rvalue.

The post-increment operator has higher precedence than the dereference operator, so you can use:

This is a concise way of writing. But this way of writing is not always available. One of the cases is the problem caused by the undefined calculation order:

7. Member access operators (dot operator and arrow operator)
The dereference operator has lower precedence than the dot operator (accessing member functions, member variables, etc.).
Arrow operators return an lvalue. The return of the dot operator varies with the type of object to which the member belongs. If the object to which the member belongs is an lvalue, the dot operator returns an lvalue. If the object to which the member belongs is an rvalue, the dot operator returns an rvalue.

8. Conditional Operators
The format is as follows:

Allows nesting of conditional operators within another conditional operator. That is, a conditional expression can be used as the cond or expr of another conditional operator. for example:

Conditional operators have very low precedence and require parentheses. otherwise:

9. Bitwise operators
In bit operations, if promotion is involved, it needs to be promoted before performing bit operations.
In view of the fact that the shift may change the value of the sign bit, there is no clear regulation on how to deal with the sign bit, which depends on the specific machine, so it is recommended to only apply the shift to unsigned numbers.

The IO operators << and >> are overloaded versions of the shift operators, and their precedence and associativity are the same as those of the shifted versions. Satisfy the left associative law, that is, operate from left to right, as for the priority:

10. sizeof operator
sizeof returns the size of the size_t type, and the operand has two forms:

sizeof satisfies the right associative law. Operates from right to left. Computing the size does not actually compute the value of the object:

11. The comma operator

12. Type conversion
Two types are associated if they can be converted to each other.

12.1 Implicit conversions

Array implicit conversion: Arrays are implicitly converted to pointers. Except in the following four cases:

Arrays as arguments to decltype
The array is used as the parameter of & amp; to take the address symbol
Array as parameter of sizeof
Array as parameter of typeid
Implicit pointer conversion: The constant integer value 0 or the literal value nullptr can be converted to any pointer type. A pointer to any non-constant can be converted to void*, and a pointer to any object can be converted to const void *.

Conversion of class type definitions:

There are two class-type conversions in the above conversions.

12.2 Arithmetic conversions
Converts one arithmetic type to another arithmetic type. For example, when using an operator, the operand is converted to the widest type.

Integer promotion: converts a small integer type to a larger integer type. bool, char, and short are all small integers, and are generally promoted to int. Larger char types such as wchar_t, char16_t, etc. will be promoted to the smallest type that can accommodate all possible values of the original type among int and long.
In the actual operation, the plastic promotion is performed first, and then the type conversion is performed.

Arithmetic conversions of unsigned types (special handling):
Both operands of an operator are signed or unsigned. Then the small type is promoted first and then turned to the large type.
The two operands of an operator are signed and unsigned:

An unsigned type is greater than or equal to (meaning literally) a signed type. Convert signed to unsigned.
Signed types are greater (meaning literally) than unsigned types. If the signed type can completely store all values of the unsigned (comparison of type size), convert the unsigned to signed. Otherwise, convert signed to unsigned.

Here is an example of an actual arithmetic conversion:

12.3 Explicit type conversions
Named casts:

type is the target type to be converted, and expression is the value to be converted. If type is a reference type, the result is an lvalue. cast-name indicates which type of conversion.

Conversion name Description
static_cast ① Any well-defined type conversion that does not include the underlying const can use this. ②It is very useful when assigning a larger arithmetic type to a smaller type. static_cast tells the reader and the compiler that they don’t care about the loss of precision, and the compiler will not give a warning.
dynamic_cast
const_cast can only change the underlying const of the operand (not so much, it is better to say that it provides another interface to access the object), and only it can change the underlying const attribute. Using other named casts to try to modify the const attribute will report an error. And const_cast can’t change the type of the object, it can only change the const attribute: The underlying const means that const_cast can only change the pointer. For constant objects, that is, the top-level const, const_cast can’t do anything.
reinterpret_cast provides bit-level reinterpretation (content unchanged, type changed). The figure below converts an int * type pointer into a char pointer, and then uses it as a char later. However, in fact, the data stored in the pc is of type int. If you try to do this: It will cause an error, because the int stored in the pc cannot complete the type conversion between char* and string. As can be seen from the above, use reinterpret_cast is more dangerous