này là vét cạn “thông minh” xài 9 vòng for
gọi count(x)
là hàm đếm số số x
trong mảng N
. Ví dụ dãy số N = {1,3,5,6,3,7,2,9,10,3,4,6}
thì count(6) = 2
nhận thấy số 10 cộng vào mod 10 thì giá trị trả về ko thay đổi nên ko cần làm vòng for cho số 10. Bài toán trở thành chọn k’ số sao cho k-count(10) <= k’ <= k
số số 1/2/3/4/5/6/7/8/9 chỉ có thể là từ 0 tới k’, cho chạy tới k’-1 thôi vì trường hợp k’ tối đa thì mấy số kia chỉ còn có thể là 0 hết, vậy cần ktra 9 trường hợp k’ tối đa riêng. k’ tối đa là 8, vậy xét số số 1/2/3/4/5/6/7/8/9 từ 0 tới 7 là được.
// cần ktra 9 trường hợp c1 = k, c2 = k, c3 = k, ..., c9 = k
for (int c1 = 0; c1 < k; ++c1) {
for (int c2 = 0; c2 < k; ++c2) {
for (int c3 = 0; c3 < k; ++c3) {
for (int c4 = 0; c4 < k; ++c4) {
for (int c5 = 0; c5 < k; ++c5) {
for (int c6 = 0; c6 < k; ++c6) {
for (int c7 = 0; c7 < k; ++c7) {
for (int c8 = 0; c8 < k; ++c8) {
for (int c9 = 0; c9 < k; ++c9) {
}
}
}
}
}
}
}
}
}
9 vòng for này chạy từ 0 tới 7, chỉ mất tối đa 8^9 ~ 134tr lần thôi
const int maxCount = k;
const int minCount = k - count(10);
int totalCount = 0;
for (int c1 = 0; c1 < k; ++c1) {
if (c1 > count(1)) continue;
totalCount = c1;
if (minCount > totalCount || totalCount > maxCount) continue;
for (int c2 = 0; c2 < k; ++c2) {
if (c2 > count(2)) continue;
totalCount = c1 + c2;
if (minCount > totalCount || totalCount > maxCount) continue;
for (int c3 = 0; c3 < k; ++c3) {
...
}
duyệt 9 vòng for khủng quá thì nghĩ cách khác duyệt 1 vòng for
nhận thấy số số x
chỉ có giá trị từ 0 tới 7, vừa vặn trong 3 bit. 9 số vừa vặn trong 27 bit. Vậy cho i
chạy từ 0
tới 2^27 - 1
là duyệt hết 8^9 số này. Lúc này c1
= 3 bit thấp nhất của i
, c2
là 3 bit thấp tiếp theo của i
, v.v…
// check 10 trường hợp k tối đa
for (int i = 1; i <= 10; ++i) {
if (k > count(i)) continue;
const int sum = i * k;
if (sum % 10 == m) {
std::cout << "FOUND\n";
break;
}
}
// nếu chưa tìm thấy thì quất tiếp vòng for này
for (unsigned int i = 0; i < (1<<27); ++i) {
int c[10] = {0}; // xài c[1] tới c[9], bỏ c[0]
bool validConfig = true;
int totalCount = 0;
int sum = 0;
for (int j = 1; j <= 9; ++j) {
// trích c[j] từ i
c[j] = (i >> (3*j - 3)) & 7);
if (c[j] > count(j)) {
validConfig = false;
break;
}
// update totalCount: thêm c[j] vào tổng số
totalCount += c[j];
if (minCount > totalCount || totalCount > maxCount) {
validConfig = false;
break;
}
// update sum
sum += j * c[j];
}
if (validConfig && sum % 10 == m) {
std::cout << "FOUND\n";
break;
}
}