Change Exactly Two Digits
Autumn Tournament (2018)
Submission name: changenumber.cpp
Problem summary
Change exactly two digit positions in a possibly signed decimal integer to obtain the largest possible integer divisible by 6. Keep its sign and number of digits; a changed digit must differ from its original value. Do not print a leading plus sign.
Source clarification. The PDF does not explicitly discuss leading zeroes in the modified number. The official author implementation preserves a nonzero first digit; this solution follows that intended convention.
Input
One integer with an optional + or − sign.
Output
The largest resulting multiple of 6.
Constraints
The input contains 2 to 100 digits. The resulting number has no leading zero.
Worked example
Official statement sample.
Input
-4321
Output
-1320
Solution analysis
- Use a string: 100-digit integers do not fit built-in numeric types. A multiple of 6 must have an even final digit and a digit sum divisible by 3.
- Enumerate the two distinct changed positions and their two replacement digits. Reject unchanged replacements, leading zeroes, odd last digits, and digit sums not divisible by 3. The sum can be updated from the original sum in constant time.
- All remaining candidates have the same length. For a positive input, lexicographically larger digits give a larger number. For a negative input, choose the lexicographically smallest absolute value instead. For −4321, changing 4 to 1 and the final 1 to 0 produces −1320; its digit sum is 6 and it is even.
- The code mutates one candidate string and restores its changed positions after trying each pair. It copies a string only when a valid candidate improves the best. This exhaustive method is straightforward enough for at most 100 digits.
Why it works
Every permitted result changes a unique pair of positions to two different replacement digits, so it is enumerated. The parity and digit-sum tests are equivalent to divisibility by 6. Equal-length lexicographic comparison orders positive magnitudes, reversed for negatives; selecting the best valid candidate therefore maximizes the signed result.
Watch out. Exactly two positions must change, even when the input already divides by 6. For a negative number maximize the signed value by minimizing its magnitude. Preserve the sign, prohibit a leading zero, and do not parse 100 digits into an integer.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<string>
using namespace std;
int main(){
string digits;
cin>>digits;
bool negative=digits[0]=='-';
if(digits[0]=='-'||digits[0]=='+'){
digits.erase(digits.begin());
}
int length=static_cast<int>(digits.size());
int digitSum=0;
for(char digit:digits){
digitSum+=digit-'0';
}
string candidate=digits;
string best;
for(int first=0;first<length;first++){
for(int second=first+1;second<length;second++){
for(char a='0';a<='9';a++){
if(a==digits[first]||(first==0&&a=='0')){
continue;
}
candidate[first]=a;
for(char b='0';b<='9';b++){
if(b==digits[second]){
continue;
}
candidate[second]=b;
int newSum=digitSum+a-digits[first]+b-digits[second];
if((candidate.back()-'0')%2!=0||newSum%3!=0){
continue;
}
// Negative numbers reverse the order of their magnitudes.
if(best.empty()||(negative?candidate<best:candidate>best)){
best=candidate;
}
}
candidate[second]=digits[second];
}
candidate[first]=digits[first];
}
}
if(negative){
cout<<'-';
}
cout<<best<<'\n';
}