Sáng kiến kinh nghiệm Lớp các bài toán cơ bản trên mảng một chiều lập trình bằng ngôn ngữ C++

I. Khái niệm

Mảng một chiều là dãy hữu hạn các phần tử có cùng kiểu dữ liệu. Khi nói đến

mảng ta cần xác định được:

- Kiểu dữ liệu của các phần tử mảng .

- Số phần tử của mảng.

II. Cách khai báo

1. Khai báo không có khởi tạo

[Số phần tử];

Ví dụ: int a[5]; float b[10];

2. Khai báo có khởi tạo

[Số phần tử] = {dãy giá trị};

Hoặc: [ ] = {dãy giá trị} ;

(Lưu ý: Trong trường hợp không khai báo số phần tử mảng thì mảng vừa đủ lớn

để giữ các giá trị được khởi tạo)

Trong đó: - Tên kiểu dữ liệu: là các kiểu dữ liệu cơ bản hoặc kiểu dữ liệu có cấu

trúc.

- Tên biến mảng: do người dùng đặt theo quy tắc đặt tên.

- Số phần tử: kích thước mảng.

Ví dụ: float x[5]={3,5,7,2,1};

int a[ ] = {0, 2, 4, 6, 8};

pdf81 trang | Chia sẻ: thuydung3ka2 | Ngày: 04/03/2022 | Lượt xem: 585 | Lượt tải: 5Download
Bạn đang xem 20 trang mẫu của tài liệu "Sáng kiến kinh nghiệm Lớp các bài toán cơ bản trên mảng một chiều lập trình bằng ngôn ngữ C++", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
; 
16. tg=di[i]; 
17. di[i]=di[j]; 
18. di[j]=tg; 
19. } 
20. res=0; 
21. for (i=1;ires) res=ti[i]+di[i]; 22. 
else res=res+di[i]; 
23. cout<<res; 
24. return 0; 
25. } 
3. Bài tập chủ đề tìm kiếm trên mảng 
Bài 21. Hướng dẫn: 
Duyệt từ đầu dãy đến cuối dãy, tìm thấy phần tử thỏa mãn là số thân thiện thì 
tăng biến đếm lên một đơn vị. 
Chương trình: 
1. #include 
2. using namespace std; 
3. int a,b,i; 
4. int dao(int n) 
5. { 
6. int t=0; 
7. while (n>0) 
8. { 
60 
9. t=t*10+n%10; 
10. n=n/10; 
11. } 
12. return t; 
13. } 
14. int main() 
15. { 
16. freopen("thanthien.inp","r",stdin); 
17. freopen("thanthien.out","w",stdout); 
18. cin>>a>>b;int d=0; 
19. for (i=a;i<=b;i++) 
20. if (__gcd(i,dao(i))==1) d++; 
21. cout<<d; 
22. } 
Bài 22. Xây hàng rào 
Hướng dẫn: 
Duyệt từ đầu 1 đến n và đếm các a[i] y, chính là số cọc chưa sử 
dụng. 
Chương trình: 
1. #include 
2. using namespace std; 
3. int i,n; 
4. float a[100000002],x,y; 
5. int main() 
6. { 
7. freopen("sococ.inp","r",stdin); 
8. freopen("sococ.out","w",stdout); 
9. cin>>n>>x>>y; 
10. for(i=1;i<=n;i++) 
11. cin>>a[i]; 
12. int d=0; 
13. for(i=1;i<=n;i++) 
14. if((a[i]y)) 
15. d++; 
16. cout<<d; 
17. } 
61 
Bài 23. Số vé 
Hướng dẫn: 
Đọc lần lượt các số x và lưu vào mảng a. Sau đó, kiểm tra nếu a[i] chia hết cho 3 
thì đó là người ngồi ghế hàng 1. Nếu a[i] < 0 và a[i] chia hết cho 2 thì đó là người 
ngồi ghế hàng 2. 
Chương trình: 
1. #include 
2. using namespace std; 
3. int n,x; 
4. int a[100000];int i,d1,d2; 
5. int main() 
6. { 
7. freopen("sove.inp","r",stdin); 
8. freopen("sove.out","w",stdout); 
9. n=0; 
10. while (cin>>x) 
11. { 
12. n++; 
13. a[n]=x; 
14. if (a[n]==0) break; 
15. } 
16. while (a[n]==0) n--; 
17. cout<<n<<endl; 
18. d1=0; d2=0; 
19. for (i=1;i<=n;i++){ 
20. if (a[i] %3==0)d1++; 
21. if ((a[i]<0) && (a[i] % 2==0)) d2++; 22. } 
23. cout<<d1<<endl; 
24. cout<<d2; 
25. return 0; 
26. } 
Bài 24. Số dầu 
Hướng dẫn: 
Tìm vị trí 0 đầu tiên và 0 cuối cùng trong dãy, sau đó tính tổng các số nằm trong 
đoạn vị trí 0 đầu tiên đến vị trí 0 cuối cùng. 
Chương trình: 
62 
1. #include 
2. using namespace std; 
3. float a[50]; 
4. 
5. int n,i,j,k,tong=0; 
6. int vttrdau () 
7. { 
8. int i=1; 
9. while((i<=n)&&(a[i]!=0)) 
10. i++; 
11. return i; 
12. } 
13. int vttrcuoi () 
14. { 
15. int i=n ; 
16. while ((i>=1) &&(a[i]!=0)) 
17. i-- ; 
18. return i ; 
19. } 
20. int main(){ 
21. freopen("sodau.inp","r",stdin); 
22. freopen("sodau.out","w",stdout); 
23. cin>>n; 
24. for (i=1 ;i>a[i]; 
25. tong=0 ; 
26. j=vttrcuoi() ; 
27. i=vttrdau() ; 
28. for (k=i;k<= j ;k++) 
29. tong=tong+a[k] ; 
30. cout << setprecision(2) << fixed << tong; 31. 
return 0; 
32. } 
Bài 25. Patuljci 
Hướng dẫn: 
Tính tổng suma các phần tử trong dãy. Sau đó, kiểm tra (suma - broj[i] - broj[j] = 
100); k khác i và k khác j hay không 
Chương trình: 
1. #include 
2. using namespace std; 
63 
3. int main() { 
4. freopen("patuljci.inp","r",stdin); 
5. freopen("patuljci.out","w",stdout); 
6. int broj[9]; 
7. int suma = 0; 
8. for( int i = 0; i < 9; ++i ) { 
9. cin>>broj[i] ; 
10. suma += broj[i]; 
11. } 
12. for( int i = 0; i < 9; ++i ) 
13. for( int j = i+1; j < 9; ++j ) 
14. if( suma - broj[i] - broj[j] == 100 ) 15. for( 
int k = 0; k < 9; ++k ) 
16. if( k != i && k != j ) 
17. cout<< broj[k] <<endl; 
18. return 0; 
19. } 
Bài 26. Shell Game 
Hướng dẫn: 
Mô phỏng chuyển động của viên sỏi dựa trên ba điểm xuất phát có thể có của nó, 
lấy điểm nào mang lại nhiều câu trả lời đúng nhất. 
Chương trình: 
1. #include 
2. using namespace std; 
3. long long n,a[10000],b[10000],c[10000]; 
4. long long p,dem,kq; 
5. void mo() 
6. { 
7. freopen("shell.inp","r",stdin); 
8. freopen("shell.out","w",stdout); 
9. } 
10. void doc() 
11. { 
12. cin>>n; 
13. for(int i=1;i<=n;i++) 
14. { 
15. cin>>a[i]>>b[i]>>c[i]; 
16. } 
17. } 
18. void xuly() 
64 
19. { 
20. kq=0; 
21. for(int k=1;k<=3;k++) 
22. { 
23. p=k;dem=0; 
24. for(int i=1;i<=n;i++) 
25. { 
26. if(p==a[i]) p=b[i]; 
27. else if(p==b[i]) p=a[i]; 
28. if(c[i]==p) dem++; 
29. } 
30. kq=max(kq,dem); 
31. } 
32. cout<<kq; 
33. } 
34. int main() 
35. { 
36. mo(); 
37. doc(); 
38. xuly(); 
39. } 
Bài 27. Tìm ước 
Hướng dẫn: 
Viết hàm kiểm tra dãy con có độ dài k là ước của dãy A. Sau đó, duyệt từ 1 đến 
n/2 để tìm k. 
Chương trình: 
1. #include 
2. using namespace std; 
3. const int N = 1e4 + 4; 
4. int n; 
5. int a[N]; 
6. bool check(int k) 
7. { 
8. for(int i = 1; i <= n - k; ++i) 
9. if(a[i] != a[i + k]) return false; 
10. return true; 
11. } 
12. int main() 
13. { 
14. ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); 
65 
15. freopen("timuoc.inp","r",stdin); 
16. freopen("timuoc.out","w",stdout); 
17. cin >> n; 
18. for(int i = 1; i > a[i]; 19. 
for(int i = 1; i <= n / 2; ++i) 
20. if(check(i)) {cout << i; return 0;} 21. 
cout << n; 
22. } 
Bài 28. Socola 
Hướng dẫn: 
- Duyệt từ 1 đến n để tính tổng thời gian ti[i] của Tí đã ăn thanh socola. - Duyệt 
từ n trở về 1 để tính tổng thời gian teo[i] của Tèo đã ăn thanh socola. 
- Duyệt từ 1 đến n so sánh ti[i] và teo[i], nếu t[i] < teo[i] thì Tí ăn thêm 1 thanh 
socola ngược lại thì Teo ăn thêm 1 thanh socola. 
Chương trình: 
1. #include 
2. using namespace std; 
3. int n; 
4. int a[100001]; 
5. int ti[100001]; 
6. int teo[100001]; 
7. int main() 
8. { 
9. freopen("socola.inp","r",stdin); 
10. freopen("socola.out","w",stdout); 
11. int d=0; 
12. cin>>n; 
13. for(int i=1;i>a[i]; 
14. ti[1]=a[1]; 
15. teo[n]=a[n]; 
16. for(int i=2;i<=n;i++) ti[i]=ti[i-1]+a[i]; 17. 
for(int i=n-1;i>=1;i--) teo[i]=teo[i+1]+a[i]; 18. 
for(int i=1;i<=n;i++) 
19. { 
20. if(ti[i]<=teo[i]) d++; 
21. else break; 
22. } 
23. cout<<d<<' '<<n-d; 
24. } 
66 
Bài 29. Herding 
Hướng dẫn: 
- Sắp xếp dãy tăng dần 
- Viết hàm tìm tmin, tmax để tìm số lần di chuyển tối thiểu và tối đa. 
Chương trình: 
25. #include 
26. using namespace std; 
27. long long a[3]; 
28. long long tmin(int x,int y,int z) 
29. { 
30. int amin; 
31. if (x + 1 == y && y + 1 == z) amin = 0; 32. else 
if (y - x == 2 || z - y == 2) amin = 1; 33. else 
amin = 2; 
34. return amin; 
35. } 
36. long long tmax(int x,int y,int z) 
37. { 
38. int k=max (y-x,z-y); 
39. return k-1; 
40. } 
41. int main() 
42. { 
43. freopen("herding.inp", "r", stdin); 
44. freopen("herding.out", "w", stdout); 
45. for (int i=1;i>a[i]; 
46. sort(a+1,a+4); 
47. cout<<tmin(a[1],a[2],a[3])<<endl; 
48. cout<<tmax(a[1],a[2],a[3]); 
49. return 0; 
50. } 
Bài 30. Mixing Milk 
Hướng dẫn: 
Có thể mô phỏng từng lần rót một, theo dõi lượng sữa trong mỗi thùng. Ví dụ, 
nếu đổ từ xô 1 vào xô 2, xô 1 có kích thước c1 và xô 2 có kích thước c2. Trước khi 
đổ, xô 1 có m1 đơn vị sữa và xô 2 có đơn vị m2, thì lượng sữa đổ là min (m1, c2 − 
m2). Do đó sau khi đổ, lượng sữa trong thùng 1 là m1 − min (m1, c2 − m2). Và lượng 
sữa trong xô 2 là m2 + min (m1, c2 − m2). Công thức đổ xô 2 vào xô 3 hoặc xô 3 vào 
xô 1 là tương tự. 
67 
Chương trình: 
1. #include 
2. using namespace std; 
3. string s; 
4. int x[5], v[5]; 
5. void pour(int a, int b) 
6. { 
7. int p = min (x[a], (v[b] - x[b])); 
8. x[a] -= p; 
9. x[b] += p; 
10. } 
11. void xl() 
12. { 
13. for (int i = 1; i <= 100; i++) 
14. { 
15. if (i % 3 == 1) pour(1, 2); 
16. if (i % 3 == 2) pour(2, 3); 
17. if (i % 3 == 0) pour(3, 1); 
18. } 
19. cout<<x[1]<<endl;; 
20. cout<<x[2]<<endl; 
21. cout<<x[3]; 
22. } 
23. int main() 
24. { 
25. freopen("mixmilk.inp", "r", stdin); 
26. freopen("mixmilk.out", "w", stdout); 
27. for (int i = 1; i <= 3; i++) 
28. cin >> v[i] >> x[i]; 
29. xl(); 
30. return 0; 
31. } 
Bài 31. New Year and Hurry 
Hướng dẫn: 
Bài này sử dụng công thức tính cấp số cộng và chặt nhị phân để giải quyết 
Chương trình: 
1. #include 
2. using namespace std; 
3. int main() 
68 
4. { 
5. freopen("newyear.inp","r",stdin); 
6. freopen("newyear.out","w",stdout); 
7. int n,k,dau,cuoi,giua, tmp,res; 
8. cin >> n >> k; 
9. int s = 240 - k; 
10. dau=0; 
11. cuoi=n; 
12. while (dau<=cuoi) 
13. { 
14. giua=(dau+cuoi)/2; 
15. tmp = 0.5*giua*(10+(giua-1)*5); 
16. if (tmp<=s) 
17. res=giua; 
18. if (tmp > s) 
19. cuoi=giua-1; 
20. else 
21. dau=giua+1; 
22. } 
23. cout << res; 
24. return 0; 
25. } 
Bài 32. Blackjack 
Hướng dẫn: 
Bài này khá đơn giản, làm bằng cách bình thường nhất là o(n
3
), có thể cải tiến 
bằng cách dùng chặt nhị phân, độ phức tạp n
2
log2n 
Chương trình: 
1. #include 
2. using namespace std; 
3. int n,m,a[1000003],dem=0,kq=0; 
4. int tim(int k,int i,int j) 
5. { 
6. int d=i+1,c=j-1,kq=0; 
7. while (d<=c) 
8. { 
9. int g=(d+c)/2; 
10. if (k+a[g]<=m) 
11. { 
12. kq=g; 
13. d=g+1; 
69 
14. } 
15. else c=g-1; 
16. } 
17. return kq; 
18. } 
19. int main() 
20. { 
21. ios::sync_with_stdio(0); 
22. cin.tie(0);cout.tie(0); 
23. freopen("Blackjack.inp","r",stdin); 
24. freopen("Blackjack.out","w",stdout); 
25. cin>>n>>m; 
26. for (int i=1;i>a[i]; 
27. sort(a+1,a+n+1); 
28. for (int i=1;i<=n;i++) 
29. for (int j=i+1;j<=n;j++) 
30. if (a[i]+a[j]<m) 
31. { 
32. int g=tim(a[i]+a[j],i,j); 
33. kq=max(kq,a[i]+a[j]+a[g]); 
34. } 
35. cout<<kq; 
36. } 
Bài 33. Cặp đôi hoàn hảo 
Hướng dẫn: 
- Sắp xếp mảng tăng dần. 
- Áp dụng thuật toán tìm kiếm nhị phân tìm phần tử lớn nhất nhưng nhỏ hơn 
hoặc bằng x. 
- Duyệt từ từ 1 đến số lượng cặp đôi thỏa mãn. 
Chương trình: 
1. #include 
2. using namespace std; 
3. long long a[100002],d,n,res=0; 
4. long long tknp1(long long a[],long long x,long long 
l,long long r) 
5. { 
6. long long d=l,c=r,g,kq=0; 
7. while(d<=c) 
8. { 
70 
9. g=(d+c)/2; 
10. if(a[g]<=x) 
11. { 
12. kq=g; 
13. d=g+1; 
14. } 
15. else c=g-1; 
16. } 
17. return kq; 
18. } 
19. int main() 
20. { 
21. freopen("capdoihh.inp","r",stdin); 
22. freopen("capdoihh.out","w",stdout); 
23. cin>>n>>d; 
24. for(int i=1;i>a[i]; 
25. sort(a+1,a+n+1); 
26. for(int i=1;i<=n;i++) 
27. { 
28. res+=tknp1(a,a[i]+d,i,n)-i; 
29. cout<<a[i]<<endl; 
30. } 
31. cout<<res; 
32. return 0; 
33. } 
Bài 34. Xếp trứng 
Hướng dẫn: 
Gọi S là tổng các ai, Min là giá trị ai nhỏ nhất, vậy kết quả bài toán nằm trong 
đoạn [Min ... S]. Dãy ai được chọn phải theo thứ tự, với mỗi giá trị của phép chặt nhị 
phân ta kiểm tra xem có thể xếp vào đúng M thùng được không. Chương trình: 
1. #include 
2. using namespace std; 
3. int kq,n,m,a[100005],s,Min; 
4. bool check(int k) 
5. { 
6. int s=0,dem=1; 
7. for(int i=1;i<=n;i++) 
8. { 
9. if(s+a[i]<=k) s+=a[i]; 
10. else 
71 
11. { 
12. if(a[i]>k) return false; 
13. dem++; 
14. if(dem>m) return false; 
15. s=a[i]; 
16. } 
17. } 
18. return true; 
19. } 
20. int main() 
21. { 
22. freopen("xeptrung.inp","r",stdin); 
23. freopen("xeptrung.out","w",stdout); 
24. cin>>n>>m; 
25. for(int i=1;i<=n;i++) 
26. { 
27. cin>>a[i]; 
28. s+=a[i]; 
29. Min=min(Min,a[i]); 
30. } 
31. int d=Min,c=s,g; 
32. while(d<=c) 
33. { 
34. g=(d+c)/2; 
35. if(check(g)) 
36. { 
37. kq=g; 
38. c=g-1; 
39. } 
40. else d=g+1; 
41. } 
42. cout<<kq; 
43. } 
Bài 35. Hàng cây 
Hướng dẫn: 
- Cách 1: Thuật toán vét cạn thử tất cả các độ cao từ cây cao nhất (maxH) tới 0. 
Với mỗi độ cao H, tính tổng số mét gỗ thu được, nếu tổng lớn hơn bằng M đầu tiên ta 
thu được độ cao cần tìm (đây là cách không đạt điểm tối đa). 
- Cách 2: Ta có nhận xét, nếu cắt ở độ cao H lấy được M mét gỗ thì khi cắt độ 
cao H- 1 cũng lấy được M mét gỗ. Ngược lại, nếu cắt ở độ cao H không lấy được M 
72 
mét gỗ thì khi cắt độ cao H+1 cũng không lấy được M mét gỗ. Từ nhận xét trên ta có 
thể sử dụng giải thuật tìm kiếm nhị phân để tìm độ cao H cao nhất cần cắt để lấy được 
M mét gỗ thỏa mãn yêu cầu bài. 
Chương trình: 
1. #include 
2. using namespace std; 
3. int n,a[1000005]; 
4. long long m; 
5. bool check(long long t) 
6. { 
7. long long kq=0; 
8. for(int i=1;i<=n;i++) 
9. if(a[i]>t) kq+=a[i]-t; 
10. if(kq>=m) return true; 
11. return false; 
12. } 
13. int tim(long long m) 
14. { 
15. int d=0,c=a[n],g,kq; 
16. while(d<=c) 
17. { 
18. g=(d+c)/2; 
19. if(check(g)) 
20. { 
21. kq=g; 
22. d=g+1; 
23. } 
24. else c=g-1; 
25. } 
26. return kq; 
27. } 
28. int main() 
29. { 
30. freopen("wood.inp","r",stdin); 
31. freopen("wood.out","w",stdout); 
32. ios::sync_with_stdio(0); 
33. cin.tie(0); 
34. cin>>n>>m; 
35. for(int i=1;i<=n;i++) 
36. cin>>a[i]; 
37. sort(a+1,a+n+1); 
73 
38. cout<<tim(m); 
39. } 
Bài 36. Wires 
Hướng dẫn: 
Ta thử lần lượt độ dài m, sau đó kiểm tra xem có cắt được K đoạn có độ dài m 
không? 
Chương trình: 
1. #include 
2. using namespace std; 
3. int n,k,ma=0,mi=1,kq=0,a[1000003]; 
4. bool kt(int m){ 
5. int d=0; 
6. for (int i=1;i<=n;i++) d+=a[i]/m; 
7. if (d>=k) return true; 
8. return false; 
9. } 
10. int main(){ 
11. ios::sync_with_stdio(0); 
12. cin.tie(0);cout.tie(0); 
13. freopen("wires.inp","r",stdin); 
14. freopen("wires.out","w",stdout); 
15. cin>>n>>k; 
16. for (int i=1;i<=n;i++) 
17. { 
18. cin>>a[i]; 
19. ma=max(ma,a[i]); 
20. } 
21. while (mi<=ma) 
22. { 
23. int g=(mi+ma)/2; 
24. if (kt(g)) 
25. { 
26. kq=g; 
27. mi=g+1; 
28. } 
29. else ma=g-1; 
30. } 
31. cout<<kq; 
32. } 
74 
Bài 37. Jump 
Hướng dẫn: 
- Gọi T[i] là phần tử nhỏ nhất từ a1 đến ai. Vậy T là dãy giảm dần. 
- Duyệt tất cả các chỉ số j từ 1 đến N. Với mỗi j ta tìm kiếm nhị phân trên trên 
đoạn chỉ số [1, j-1] của dãy T phần tử lớn nhất thỏa mãn ≤ a[j]-p. 
Chương trình: 
1. #include 
2. using namespace std; 
3. const int maxn=100000; 
4. int a[maxn],t[maxn],n,p,kq,i,j; 
5. int tknp(int l,int h) 
6. { 
7. int tg,dau,cuoi,giua; 
8. tg=h; 
9. dau=1; 
10. cuoi=h-1; 
11. while (dau<=cuoi) 
12. { 
13. giua=(dau+cuoi) / 2; 
14. if (t[giua]<=a[h]-p) 
15. { 
16. tg=giua; 
17. cuoi=giua-1; 
18. } 
19. else dau=giua+1; 
20. } 
21. return tg; 
22. } 
23. int main () 
24. { 
25. freopen("jump.inp","r",stdin); 
26. freopen("jump.out","w",stdout); 
27. cin>>n>>p; 
28. for (i=1;i>a[i]; 
29. t[1]=a[1]; 
30. for (i=2;i<=n;i++) 
31. t[i]=min(t[i-1],a[i]); 
32. kq=0; 
33. for (i=2;i<=n;i++) 
34. { 
75 
35. j=tknp(1,i); 
36. if (i-j>kq) kq=i-j; 
37. } 
38. 
39. cout<<kq; 
40. return 0; 
41. } 
Bài 38. Dãy số 
Hướng dẫn: 
- Trước hết tính tổng các số từ 1 đến n và lưu vào mảng f - 
Sắp xếp mảng f 
- Áp dụng thuật toán tìm kiếm nhị phân để tìm số cặp (i, j) 
Chương trình: 
1. #include 
2. using namespace std; 
3. long long res,n,l,r,a[100005],d,c,k,g,l1,r1; 
4. long long f[100005]; 
5. int main() 
6. { 
7. memset(f,0,sizeof(f)); 
8. freopen("seq.inp","r",stdin); 9. 
freopen("seq.out","w",stdout); 10. 
cin>>n>>l>>r; 
11. for(int i=1;i<=n;i++) 
12. cin>>a[i]; 
13. f[0]=0; 
14. f[1]=a[1]; 
15. for(int i=2;i<=n;i++) 
16. { 
17. f[i]=f[i-1]+a[i]; 
18. } 
19. sort(f,f+n+1); 
20. for(int i=1;i<=n;i++) 
21. { 
22. l1=i-1;r1=0; 
23. d=0;c=i-1; 
24. while(d<=c) 
25. { 
26. g=(d+c)/2; 
76 
27. if(f[i]-f[g]<l) 
28. { 
29. c=g-1; 
30. l1=g-1; 
31. } 
32. else d=g+1; 
33. } 
34. d=0;c=i-1; 
35. while(d<=c) 
36. { 
37. g=(d+c)/2; 
38. if(f[i]-f[g]>r) 
39. { 
40. d=g+1; 
41. r1=g+1; 
42. } 
43. else c=g-1; 
44. } 
45. if(l1 >= r1) res+=l1-r1+1; 
46. } 
47. cout<<res; 
48. } 
Bài 39. Cho thuê máy 
Hướng dẫn: 
- Sắp xếp mảng a, b bằng thuật toán quicksort. 
- Dùng thuật toán tìm kiếm nhị phân để tìm tổng thời gian thực hiện lớn nhất. 
Chương trình: 
1. #include 
2. using namespace std; 
3. long long i,j,n,a[1000000],b[1000000],k[1000000],mx; 
4. long long np(long long x,long long y) 
5. { 
6. long long res=0; 
7. long long l=x,r=y; 
8. while(l<=r) 
9. { 
10. long long g=(l+r)/2; 
11. if(b[g]<=a[y]) {res=g;l=g+1;} 
12. else r=g-1; 
13. } 
14. return res; 
77 
15. } 
16. void quicksort(long long a[],long long b[],long long 
l,long long r) 
17. { 
18. i=l;j=r; 
19. long long x=a[(l+r)/2]; 
20. do 
21. { 
22. while(a[i]<x)i++; 
23. while(a[j]>x) j--; 
24. if(i<=j) 
25. { 
26. swap(a[i],a[j]); 
27. swap(b[i],b[j]); 
28. i++;j--; 
29. } 
30. } 
31. while(i<=j); 
32. if(l<j) quicksort(a,b,l,j); 
33. if(i<r) quicksort(a,b,i,r); 
34. } 
35. int main() 
36. { 
37. freopen("max.inp","r",stdin); 
38. freopen("max.out","w",stdout); 
39. cin>>n; 
40. k[0]=0; 
41. for(int i=1;i<=n;i++) 
42. cin>>a[i]>>b[i]; 
43. quicksort(b,a,1,n); 
44. k[1]=b[1]-a[1]; 
45. mx=k[1]; 
46. for(int i=2;i<=n;i++) 
47. { 
48. k[i]=b[i]-a[i]+k[np(1,i)]; 
49. mx=k[i]=max(k[i],mx); 
50. } 
51. cout<<mx; 
52. return 0; 
53. } 
78 
Bài 40. Làm gốm 
Hướng dẫn: Nhận xét rằng tất cả các sản phẩm đều phải nặn xong mới chuyển 
sang vẽ do vậy trong ngày làm việc khoảng thời gian đầu, công nhân xưởng vẽ được 
nghỉ và khoảng thời gian sau, công nhân xưởng nặn được nghỉ. 
Đặt S là khoảng thời gian làm việc của công nhân xưởng nặn. Khi đó khoảng 
thời gian làm việc của công nhân xưởng vẽ là T-S. 
Với thời gian S, xưởng nặn làm được tối đa là: 
      
S S S 
f(S)= 
    
+ + +  
 
     
sản phẩm 
... 
a a a 
1 2 n 
và với thời gian T-S thì xưởng vẽ làm được tối đa: 
      − − − 
T S T S T S 
    
+ + +   
     
sản phẩm
g(S)= 
... 
b b b 
1 2 
m 
Điều kiện để số sản phẩm được hoàn thành hết trong ngày là h(S)=g(S)-f(S)≥0. 
Nhận xét rằng hàm h(S) là hàm đơn điệu giảm theo S. Hơn nữa nếu S càng lớn thì số 
sản phẩm làm ra được càng nhiều (bằng f(S)). Do vậy ta có thể sử dụng tìm kiếm nhị 
phân để tìm thời điểm lớn nhất S mà h(S)≥0. 
Sau khi tìm được S, giá trị cần tìm là f(S) 
Chương trình : 
1. #include 
2. #define int long long 
3. using namespace std; 
4. int a[100005], t, m, n, s, b[100005]; 
5. int g(int x) 
6. { 
7. int i, kq; 
8. kq = 0; 
9. for (i = 1; i<= m; i++) kq = kq + x/b[i]; 10. 
return kq; 
11. } 
12. int f(int x) 
13. { 
14. int i, kq; 
15. kq = 0; 
16. for (i = 1; i<= n; i++) kq = kq + x/a[i]; 17. 
return kq; 
18. } 
19. main() 
79 
20. { 
21. freopen("pottery.inp", "r", stdin); 
22. freopen("pottery.out", "w", stdout); 
23. cin >> t >> n; 
24. for(int i = 1; i > a[i]; 25. 
cin >> m; 
26. for(int i = 1; i > b[i]; 27. 
int lo, hi, mid; 
28. if (g(0)-f(t)>=0) 
29. { 
30. s = t; 
31. return 0; 
32. } 
33. lo = 0; hi = t; 
34. do 
35. { 
36. mid =(lo+hi) / 2; 
37. if (g(t - mid)-f(mid) >= 0) lo = mid; 38. else 
hi = mid; 
39. } 
40. while (hi-lo != 1); 
41. s = lo; 
42. cout << f(s); 
43. } 
4. Bài tập chủ đề tìm đoạn con dài nhất thỏa mãn điều kiện cho trước. 
Bài 41. Tìm dãy con đơn điệu 
Hướng dẫn: 
Duyệt từ i bằng 2 đến n và kiểm tra nếu a[i] <= a[i-1] thì cập nhật lại đoạn mới, 
ngược lại độ dài đoạn con tăng lên 1. Độ dài đoạn con cần tìm là max độ dài của các 
đoạn con. 
Chương trình: 
1. #include 
2. using namespace std; 
3. int n,i, len=1, maxlen=1; 
4. int a[100000]; 
5. int main () 
6. { 
7. freopen ("dondieutang.inp", "r", stdin); 8. 
freopen ("dondieutang.out", "w", stdout); 
80 

File đính kèm:

  • pdfsang_kien_kinh_nghiem_lop_cac_bai_toan_co_ban_tren_mang_mot.pdf
Sáng Kiến Liên Quan