Cần giúp đỡ bài tập tìm một số nguyên dương không quá n có tổng các chữ số lớn nhất

Nhập một số nguyên dương n.
Tìm một số nguyên dương <= n sao cho tổng của các chữ số trong số nguyên dương đó là lớn nhất

Nhồi số 9 nhiều vào là win chặt luôn :smiley:

3 Likes

cái này dạng như tính tổng từng số một nó chạy vòng lặp nhiều quá không biết làm sao h :frowning:

Khi n không có dạng (k+1)*10^d - 1, ta thấy rằng k*10^d - 1 là đáp án với tổng số chữ số là 9(d-1) + k-1 = 9d + k - 10. Giả sử tồn tại một số nhỏ hơn n nhưng có tổng chữ số là 9d + k - 9 = 9(d-1) + k. Mà chữ số thập phân không thể quá 9 và k cũng vậy, suy ra mâu thuẫn.

5 Likes

Tôi k biết C++, tôi đang code = java.
Mong mn cùng thảo luận
:smiley:

public class MainClass {
	public static void main(String[] args) {
		timSo(8899);
	}
	private static int loga(int n) {
		int i = 0;
		while (n > 0) {
			n=n/10;
			i++;
		}
		return i;
	}
	private static int timSo(int n) {
		int soChuSo = loga(n);
		int heso = (int)Math.pow(10, soChuSo-1);
		int ketQua =0;
		while (soChuSo > 1) {
			soChuSo--;
			ketQua += 9*(int)Math.pow(10, soChuSo -1);
		}
		ketQua = ((n/heso) * heso + ketQua <= n) ? ((n/heso) * heso + ketQua) : ((n/heso - 1) * heso + ketQua);
		System.out.println("So lon nhat la: " + ketQua);
		return ketQua; //7999
	}
}
1 Like

Dù em mới học không biết java nhưng em cũng cảm ơn bác vì giúp em nhé

Để nghiên cứu phát :smiley:

ketqua “sơ bộ” 99…9 lấy heso - 1 là ra rồi mà

3 dòng :horse::

int tens = 1;
while (tens <= n) tens *= 10;
return (n + 1) % (tens /= 10) ? n - n % tens - 1 : n;
3 Likes

mn cùng thảo luận về thuật toán thôi, chứ ngôn ngữ nào cũng giống nhau mà, chỉ khác syntax.
Tôi cũng chưa biết cách của mình đã phải tối ưu chưa.
Ý tưởng:
Tìm n là số có bao nhiêu chữ số.
VS: n = 8899 => có 4 chữ số
KQ = a999.
Ở đây a = 8 (chữ số đầu tiên của n) hoặc a = 7 (số đầu tiên của n - 1). So sánh KQ với 2 trường hợp của a với n.
Cách làm này có vẻ k tốt về hiệu năng. mn cùng thảo luận nhé

2 Likes

n - n % tens - 1 : n thôi :slight_smile:

5 Likes

ko có nút likeee mạnh :joy:

3 Likes

Tôi thấy chưa ổn.
while (tens <= n) tens *= 10
phải thêm tens /= 10;

return (n + 1) % (tens /= 10) ? n - n % tens - 1 : n;
điều kiện trước dấu ? chưa phải là 1 biểu thức boolean.

Trong trường hợp ngta yêu cầu KQ phải là số lớn nhất thì làm như thế nào các bạn.
VD: n = 989 // KQ phải trả về là 989 chứ k phải 899
Ai có ý tưởng gì k nhỉ?

đúng rồi, có “ăn gian” chia 10 ở dòng return đó :joy: C++ nó lỏng lẻo ở chỗ cho phép chuyển int thành bool, int có giá trị khác 0 là true, 0 là false, nếu Java thì thêm > 0 thành (n + 1) % (tens /= 10) > 0 ? ... hay != 0 cũng đc, C++ thì ko cần thiết

số lớn nhất thì tính digitSum(n) có bằng digitSum(…999) thì trả về n là xong :V :V

ý ko đc, có trường hợp
n=797 cachedBrute=789 fast=699
:V :V

n=998 cachedBrute=998 fast=899
n=997 cachedBrute=989 fast=899
n=996 cachedBrute=989 fast=899
n=995 cachedBrute=989 fast=899
n=994 cachedBrute=989 fast=899
n=993 cachedBrute=989 fast=899
n=992 cachedBrute=989 fast=899
n=991 cachedBrute=989 fast=899
n=990 cachedBrute=989 fast=899
n=989 cachedBrute=989 fast=899
n=898 cachedBrute=898 fast=799
n=897 cachedBrute=889 fast=799
n=896 cachedBrute=889 fast=799
n=895 cachedBrute=889 fast=799
n=894 cachedBrute=889 fast=799
n=893 cachedBrute=889 fast=799
n=892 cachedBrute=889 fast=799
n=891 cachedBrute=889 fast=799
n=890 cachedBrute=889 fast=799
n=889 cachedBrute=889 fast=799
n=798 cachedBrute=798 fast=699
n=797 cachedBrute=789 fast=699
n=796 cachedBrute=789 fast=699
n=795 cachedBrute=789 fast=699
n=794 cachedBrute=789 fast=699
n=793 cachedBrute=789 fast=699
n=792 cachedBrute=789 fast=699
n=791 cachedBrute=789 fast=699
n=790 cachedBrute=789 fast=699
n=789 cachedBrute=789 fast=699
n=698 cachedBrute=698 fast=599
n=697 cachedBrute=689 fast=599
n=696 cachedBrute=689 fast=599
n=695 cachedBrute=689 fast=599
n=694 cachedBrute=689 fast=599
n=693 cachedBrute=689 fast=599
n=692 cachedBrute=689 fast=599
n=691 cachedBrute=689 fast=599
n=690 cachedBrute=689 fast=599
n=689 cachedBrute=689 fast=599
n=598 cachedBrute=598 fast=499
n=597 cachedBrute=589 fast=499
n=596 cachedBrute=589 fast=499
n=595 cachedBrute=589 fast=499
n=594 cachedBrute=589 fast=499
n=593 cachedBrute=589 fast=499
n=592 cachedBrute=589 fast=499
n=591 cachedBrute=589 fast=499
n=590 cachedBrute=589 fast=499
n=589 cachedBrute=589 fast=499
n=498 cachedBrute=498 fast=399
n=497 cachedBrute=489 fast=399
n=496 cachedBrute=489 fast=399
n=495 cachedBrute=489 fast=399
n=494 cachedBrute=489 fast=399
n=493 cachedBrute=489 fast=399
n=492 cachedBrute=489 fast=399
n=491 cachedBrute=489 fast=399
n=490 cachedBrute=489 fast=399
n=489 cachedBrute=489 fast=399
n=398 cachedBrute=398 fast=299
n=397 cachedBrute=389 fast=299
n=396 cachedBrute=389 fast=299
n=395 cachedBrute=389 fast=299
n=394 cachedBrute=389 fast=299
n=393 cachedBrute=389 fast=299
n=392 cachedBrute=389 fast=299
n=391 cachedBrute=389 fast=299
n=390 cachedBrute=389 fast=299
n=389 cachedBrute=389 fast=299
n=298 cachedBrute=298 fast=199
n=297 cachedBrute=289 fast=199
n=296 cachedBrute=289 fast=199
n=295 cachedBrute=289 fast=199
n=294 cachedBrute=289 fast=199
n=293 cachedBrute=289 fast=199
n=292 cachedBrute=289 fast=199
n=291 cachedBrute=289 fast=199
n=290 cachedBrute=289 fast=199
n=289 cachedBrute=289 fast=199
n=198 cachedBrute=198 fast=99
n=197 cachedBrute=189 fast=99
n=196 cachedBrute=189 fast=99
n=195 cachedBrute=189 fast=99
n=194 cachedBrute=189 fast=99
n=193 cachedBrute=189 fast=99
n=192 cachedBrute=189 fast=99
n=191 cachedBrute=189 fast=99
n=190 cachedBrute=189 fast=99
n=189 cachedBrute=189 fast=99
n=98 cachedBrute=98 fast=89
n=88 cachedBrute=88 fast=79
n=78 cachedBrute=78 fast=69
n=68 cachedBrute=68 fast=59
n=58 cachedBrute=58 fast=49
n=48 cachedBrute=48 fast=39
n=38 cachedBrute=38 fast=29
n=28 cachedBrute=28 fast=19
n=18 cachedBrute=18 fast=9

dường như là nó + 1 vào hàng cao nhất, chuyển bớt số 1 từ hàng nào cho <= n là được

3 Likes

VD tens = 1000
Vậy là tens/10 ở trước ? là 100, vậy sau dấu ? tens = 100 hay 1000 vậy bạn?
return của bạn mình đã sửa thành
((n+1) / tens * tens - 1) <= n ? (n+1) / tens * tens - 1 : n;

4 Likes

sau dấu ? tens = 100

ở trước đó: tens /= 10 là gán tens = tens / 10, rồi tính giá trị (n+1)% tens

(n + 1) % (tens /= 10) ?
có nghĩa là
tính a = n + 1 và b = tens /= 10 cùng lúc (ko theo thứ tự trái phải hay phải trái)
tính c = a % b
xét c != 0

3 Likes

à, tôi k để ý có dấu “=”
thanks

2 Likes

ăn gian 1 dòng tens /= 10 đó mà :rofl:

3 Likes
int fast(int n) { // n > 0
    int tens = 1;
    while (tens <= n) tens *= 10;
    int ret = (n + 1) % (tens /= 10) ? n - n % tens - 1 : n;
    int ret2 = ret + tens;
    for (int t = 1; t < tens; t *= 10)
        if (ret2 - t <= n)
            return ret2 - t;
    return ret;
}

số lớn nhất <= n có tổng các chữ số lớn nhất :V

cộng tens lại thành a999…99, rồi trừ t = 1, 10, 100, …, được kết quả <= n thì return giá trị mới, còn ko thì return giá trị cũ (a-1)999…99 :V

test drive n=1 tới 100 triệu: https://rextester.com/AOQOD93360

code xogn rồi nghĩ ra cách chứng minh cũng dễ:
(a-1)999…99 là số có tổng chữ số lớn nhất mà <= n, và cũng là số lớn nhất mà < a000…00
với các số > a000…00, số có tổng các chữ số bằng (a-1)999…99 sẽ có dạng chữ số a đầu tiên, 1 chữ số 8, còn lại toàn chữ số 9. Vậy từ (a-1)999…99 ta chuyển thành a999…99 rồi trừ từ từ t=1,10,100,… tới khi nào ra số <= n là được, nếu ko có thì ko có số > a000…00 mà có tổng các chữ số lớn nhất, trả về (a-1)999…99

có thể rút gọn thành 5 dòng :V

int fast(int n) { // n > 0
    int tens = 1;
    while (tens <= n) tens *= 10;
    int ret = (n + 1) % (tens /= 10) ? n - n % tens - 1 + tens : n + tens;
    for (int t = 1; t <= tens; t *= 10)
        if (ret - t <= n) return ret - t;
    // return 0; //never reach, kệ bà compiler nó hú
}

+ tens ở trong ? : để tránh undefined behavior :V

5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?