1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Một số bài toán bồi dưỡng HSG tin học 11

20 53 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 20
Dung lượng 742,67 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Lý do chọn đề tài Để giải các bài toán nói chung và các bài toán trong Tin học nói riêng thì việc xác định Thuật toán để giải bài toán là công việc đặc biệt quan trọng.. Việc này có ngh

Trang 1

SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HOÁ

TRƯỜNG THPT HÀM RỒNG

SÁNG KIẾN KINH NGHIỆM

MỘT SỐ BÀI TOÁN BỒI DƯỠNG HỌC SINH GIỎI

MÔN TIN HỌC 11

Người thực hiện: Nguyễn Thị Mai Hương Chức vụ: Giáo viên

SKKN thuộc lĩnh mực (môn): Tin học

THANH HOÁ NĂM 2021

Trang 2

MỤC LỤC

A ĐẶT VẤN ĐỀ 1

1 Lý do chọn đề tài 1

2 Đối tượng và phạm vi nghiên cứu 1

3 Phương pháp nghiên cứu 1

B NỘI DUNG 2

Bài 1 Nộp hồ sơ đại học 2

Bài 2 Khối lập phương 4

Bài 3: Biến đổi dãy số 6

Bài 4 Look and Say 11

Bài 5 Dãy hoàn hảo 13

C KẾT LUẬN 16

Trang 3

1

TÊN ĐỀ TÀI:

MỘT SỐ BÀI TOÁN BỒI DƯỠNG HỌC SINH GIỎI

MÔN TIN HỌC 11

A ĐẶT VẤN ĐỀ

1 Lý do chọn đề tài

Để giải các bài toán nói chung và các bài toán trong Tin học nói riêng thì việc xác định Thuật toán để giải bài toán là công việc đặc biệt quan trọng Việc này có nghĩa là muốn giải các bài toán trong Tin học trước hết ta phải giải được các bài toán này ở góc độ Toán học, khi đó mới hình thành Thuật toán để cài đặt vào chương trình trên máy tính

Đối với học sinh các trường THPT, chương trình Tin học 11 cung cấp cho học sinh cách tư duy và giải các bài toán với sự hỗ trợ của các Ngôn ngữ lập trình

cụ thể là Ngôn ngữ lập trình PASCAL, C++ Đây cũng chính là ngôn ngữ được sử dụng để tham gia kỳ thi học sinh giỏi tỉnh môn Tin học Vấn đề đặt ra là với chương trình lớp 11 ở các nhà trường THPT chỉ được học trong 1 năm nên để sử dụng nhuần nhuyễn ngôn ngữ lập trình để tiến hành cài đặt các thuật toán học sinh phải va chạm với tương đối nhiều với một hệ thống bài tập Vì thế việc đưa ra hệ thống bài tập để học sinh có thể thực hành nhiều hơn, từ đó sử dụng linh hoạt ngôn ngữ lập trình khi cài đặt Thuật toán trên máy tính là rất cần thiết

2 Đối tượng và phạm vi nghiên cứu

- Môn Tin học lớp 11 ở trường THPT;

- Học sinh đội tuyển tin học khối 11 trường THPT Hàm Rồng;

3 Phương pháp nghiên cứu

- Phân tích, tổng hợp, khảo sát

- Đánh giá so sánh kết quả của học sinh;

Trang 4

2

B NỘI DUNG

Bài 1 Nộp hồ sơ đại học

Có M thí sinh đang nộp hồ sơ vào đại học Có N bàn làm việc để nhận hồ sơ của các thí sinh Bàn thứ k cần mất Tk giây để xử lí xong hồ sơ của một thí sinh Tại thời điểm 0, tất cả các bàn làm việc đều trống M thí sinh xếp hàng, và một thí sinh có thể đến ngay một bàn làm việc còn trống để nộp hồ sơ Bàn làm việc đó sẽ mất Tk giây để xử lí hồ sơ của thí sinh đó, và lại trống sau Tk giây để sẵn sàng nhận

hồ sơ tiếp theo Bạn hãy tính xem sau ít nhất bao nhiêu giây tất cả các thí sinh có thể nộp xong hồ sơ nhé

Input: Từ tệp NOPHOSO.INP gồm

- Dòng đầu tiên chứa hai số nguyên N và M (1≤N≤105; 1≤M≤109

)

- N dòng tiếp theo, dòng thứ k chứa số nguyên Tk (1≤Tk≤109

)

Output: In ra một số nguyên duy nhất là thời gian ngắn nhất để xử lí tất cả các hồ

Ví dụ:

01 2 6

7

10

18

02 7 10

3

8

3

6

9

2

4

8

Trang 5

3

Giải thích test 01:

7 1 Xong hồ sơ thí sinh 1, nhận hồ sơ thí sinh 3

10 2 Xong hồ sơ thí sinh 2, nhận hồ sơ thí sinh 4

14 1 Xong hồ sơ thí sinh 3, nhận hồ sơ thí sinh 5

21 1 Xong hồ sơ thí sinh 5, nhận hồ sơ thí sinh 6

Ý tưởng tham khảo:

Chặt nhị phân thời gian, với mỗi giá trị thời gian X tính coi dãy N sẽ xử lý được bao nhiêu hồ sơ và có lớn hơn hoặc bằng M hay không

Chương trình tham khảo:

#include <bits/stdc++.h>

#define Nekan "application"

#define fi first

#define se second

#define pb push_back

#define LL long long

#define pii pair<int,int>

#define forr(i,a,b) for(int i=(a);i<=(b);++i)

#define ford(i,a,b) for(int i=(a);i<(b);++i)

#define bacc(i,a,b) for(int i=(a);i>=(b); i)

const int N=1e5+5;

const long long MOD=1e9+7;

using namespace std;

int n, m;

int a[N];

void xuly()

{

cin>>n>>m;

forr(i,1,n) cin>>a[i];

LL L= 1, R= 1e18, res= 1;

Trang 6

4

while (L <= R)

{

LL mid= (l+r)/2;

LL sum= 0;

forr(i,1,n)

sum+= mid/a[i];

if (sum >= m)

{

R= mid-1;

ans= mid;

}

else L= mid+1;

}

cout<<res;

}

int main()

{

ios_base::sync_with_stdio(false);

cin.tie(0);cout.tie(0);

freopen(Nekan".inp","r",stdin);

freopen(Nekan".out","w",stdout);

xuly();

}

Bài 2 Khối lập phương

Quà sinh nhật của Jimmy là một bộ khối lập phương xếp hình Jimmy xếp

thành n tháp, tháp thứ i có độ cao là a i (1 ≤ ai ≤ 109, 1 ≤ n ≤ 105

, i =1 ÷ n) Jimmy rất có cảm tình với số nguyên k, vì vậy dãy liên tục các tháp được coi là hài hòa nếu chúng có độ cao trung bình là k (1 ≤ k ≤ 109

)

Yêu cầu: Cho n, k và a i , i =1 ÷ k Hãy xác định dãy tháp hài hòa dài nhất, chỉ ra

tháp đầu tiên và độ dài của dãy tìm được Nếu tồn tại nhiều dãy cùng độ dài thì chỉ

ra dãy tháp có vị trí đầu nhỏ nhất Nếu không tồn tại dãy tháp thì đưa ra một số 0

Input: Vào từ file văn bản CUBICS.INP:

Trang 7

5

- Dòng đầu tiên chứa 2 số nguyên n và k,

- Dòng thứ 2 chứa n số nguyên a 1 , a 2 , , a n

Output: Đưa ra file văn bản CUBICS.OUT trên một dòng 2 số nguyên: độ dài của dãy tìm được và số thứ tự của tháp đầu tiên hoặc một số 0 nếu không tồn tại dãy

Ví dụ:

CUBICS.INP CUBICS.OUT

5 3

1 2 3 4 6

3 2

Ý tưởng tham khảo:

Trừ mỗi phần tử A[i] đi K để đổi thành bài toán tìm đoạn con dài nhất có tổng bằng 0, bởi một đoạn độ dài L có tổng bằng 0 nghĩ là tổng của đoạn đó ban đàu bằng K*L => đoạn có có trung bình cộng là K

Chương trình tham khảo:

#include <bits/stdc++.h>

#define Nekan "cubics"

#define fi first

#define se second

#define pb push_back

#define LL long long

#define pii pair<int,int>

#define forr(i,a,b) for(int i=(a);i<=(b);++i)

#define ford(i,a,b) for(int i=(a);i<(b);++i)

#define bacc(i,a,b) for(int i=(a);i>=(b); i)

const int N=1e5+5;

const long long MOD=1e9+7;

using namespace std;

int n, k, ans, L;

LL a[N];

map <LL, int> m;

void xuly()

{

cin>>n>>k;

LL s= 0;

forr(i,1,n)

{

cin>>a[i];

a[i]-= k;

a[i]+= a[i-1];

Trang 8

6

if (a[i] != 0 && m[a[i]] == 0) m[a[i]] = i;

if (i - m[a[i]] >= ans)

{

if (i - m[a[i]] > ans)

L= m[a[i]] + 1;

else if (L > m[a[i]] + 1) L= m[a[i]] + 1;

ans= i - m[a[i]];

}

}

if (ans == 0) cout<<"0";

else

cout<<ans<<" "<<L;

}

int main()

{

ios_base::sync_with_stdio(false);

cin.tie(0);cout.tie(0);

freopen(Nekan".inp","r",stdin);

freopen(Nekan".out","w",stdout);

xuly();

}

Bài 3: Biến đổi dãy số

Cho dãy số nguyên Một phép biến đổi là tăng giá trị của phần tử nào đó lên 1 đơn vị Hãy tìm cách thực hiện ít phép biến đổi nhất để thu được một

dãy số mới trong đó có h số liên tiếp nhau tạo thành một dãy tăng dần từ 1 đến h, tức là tồn tại một vị trí i sao cho

Input: Vào từ file văn bản INCREASING.INP:

- Dòng đầu tiên chứa hai số nguyên n và h (

- Dòng thứ hai chứa n số nguyên

Output: Ghi ra file văn bản INCREASING.OUT một số nguyên duy nhất là số

phép biến đổi ít nhất cần thực hiện để có một dãy mới theo yêu cầu Nếu không có cách biến đổi thì in ra -1

Ví dụ:

INCREASING.INP INCREASING.OUT

4 3

1 1 0 2

3

Trang 9

7

Ý tưởng tham khảo:

Duyệt qua tất cả các đoạn liên tiếp độ dài h, ta sẽ kiểm tra xem đoạn [i,i+h-1] có thể đưa về dạng như yêu cầu hay không , nếu được thì cập nhật kết quả

Để kiểm tra đoạn [i, i+h-1] có thỏa hay không ta có vài nhận xét như sau: Chỉ có thao tác tăng 1 phần tử bất kì lên 1 đơn vị, cho nên điều kiện cần để đoạn [i, i+h-1] có thể đưa về đoạn đúng yêu cầu là a[i] <= 1; a[i+1] <= 2; a[i+2]<=3; … a[i+h-1] <= h

Phân tích thêm 1 chút ta có a[i] - 1 <= 0 ; a[i+1] - 2 <= 0; a[i+2] - 3 <= 0; (1)

Để đảm bảo điều kiện (1), thì max (a[i] - 1, a[i+1]-2, a[i+2]-3, , a[i+h-1]-h) phải <= 0

Để giảm a[i] đi 1, a[i+1] đi 2, a[i+2] đi 3, ta có nhận xét sau :

sử dụng sliding window : với h = 4 và dãy : a b c d e f g

với đoạn [1,4] ta có dãy mới : a-1 b-2 c-3 d-4 e f g

với đoạn [2,5] ta có dãy mới : a-0 b-1 c-2 d-3 e-4 f g

với đoạn [3,5] ta có dãy mới : a b-0 c-1 d-2 e-3 f-4 g

Như vậy, khi đi từ đoạn [i, i+h-1] sang đoạn [i+1, i+h] , tất cả các phần tử từ

i đến i + h - 1 được tăng lên 1, và phần tử i + h bị trừ đi h

Nếu max(a[i]) của đoạn [i, i+h-1] <= 0 thì đoạn này có thể đưa về theo yêu cầu, lúc này chi phí sẽ là

(1 - a[i]) + (2 - a[i+1]) + (3 - a[i+2]) + + (h - a[i+h-1])

= 1 + 2 + 3 + + h - (a[i] + a[i+1]+ a[i+2] + + a[i+h-1])

= h * (h+1) / 2 - (F[i + h - 1] - F[i-1])

trong đó F[i] = F[i-1] + a[i]

Chương trình tham khảo:

#include <bits/stdc++.h>

#define EL cout<<'\n'

#define pli pair<ll,int>

#define pll pair<ll,ll>

#define pii pair<int,int>

#define pb push_back

#define mp make_pair

#define fi first

#define se second

#define sz(a) int(a.size())

Trang 10

8

#define FU(x,a,b) for(int x=int(a);x<=int(b);x++)

#define FD(x,a,b) for(int x=int(a);x>=int(b);x )

#define PROB "INCREASING"

using namespace std;

typedef long long ll;

typedef double db;

template <typename T>

inline void read(T& x){

bool Neg = false;

char c;

for (c = getchar(); c < '0' | c > '9'; c = getchar())

if (c == '-') Neg = !Neg;

x = c - '0';

for (c = getchar(); c >= '0' && c <= '9'; c = getchar())

x = x * 10 + c - '0';

if (Neg) x = -x;

}

template <typename T>

inline void write(T x)

{

if (x < 0)

{

putchar('-'); x = -x;

}

T p = 1;

for (T temp = x / 10; temp > 0; temp /= 10) p *= 10;

for (; p > 0; x %= p, p /= 10) putchar(x / p + '0');

}

void setIO() {

ios_base::sync_with_stdio(0);

cin.tie(0); cout.tie(0);

if(fopen(PROB".inp", "r")){

freopen(PROB".inp", "r",stdin);

freopen(PROB".out", "w",stdout);

}

}

const int N = 200002;

Trang 11

9

int n, h, a[N];

ll f[N], st[N * 4], lz[N * 4];

void readinp(){

cin >> n >> h;

FU(i, 1, n) cin >> a[i];

}

void down(int id){

ll t = lz[id];

st[id * 2]+= t;

lz[id * 2]+= t;

st[id * 2 + 1]+= t;

lz[id * 2 + 1]+= t;

lz[id] = 0;

}

void upd (int id, int l, int r, int u, int v, ll g){

if (r < u || v < l) return;

if (u <= l && r <= v){

st[id]+= g;

lz[id]+= g;

return;

}

down(id);

int mid = (l + r) / 2;

upd(id * 2, l, mid, u, v, g);

upd(id * 2 + 1, mid + 1, r, u, v, g);

st[id] = max(st[id * 2], st[id * 2 + 1]);

}

ll get (int id, int l, int r, int u, int v){

if (r < u || v < l) return -1e18;

if (u <= l && r <= v) return st[id];

down(id);

int mid = (l + r) / 2;

ll t1 = get(id * 2, l, mid, u, v);

ll t2 = get(id * 2 + 1, mid + 1, r, u, v);

return max(t1, t2);

}

Trang 12

10

void build (int id, int l, int r){

if (l == r){

st[id] = a[l];

return;

}

int mid = (l + r) / 2;

build(id * 2, l, mid);

build(id * 2 + 1, mid + 1, r);

st[id] = max(st[id * 2], st[id * 2 + 1]);

}

void solve(){

FU(i, 1, n) f[i] = f[i-1] + ll(a[i]);

build(1, 1, n);

ll res = 1e18;

FU(i, 1, h - 1) upd(1, 1, n, i, i, - i);

FU(i, h, n){

int j = i - h + 1;

upd(1, 1, n, i, i, -h);

if (get(1, 1, n, j, i) <= 0){

res = min(res, ll(h) * ll(h+1) / 2LL - f[i] + f[j-1]);

}

upd(1, 1, n, j, i, 1);

}

cout << (res == 1e18 ? -1 : res);

}

int main(){

setIO();

int t = 1;

// cin >> t;

while (t ){

readinp();

solve();

}

}

Trang 13

11

Bài 4 Look and Say

Học đã giỏi, Bo tự nghĩ ra cho mình một cách viết số mới Từ trái sang phải,

Bo đếm số lượng chữ số liên tiếp bằng nhau và ghi số lượng sô chữ số đó và kế tiếp theo là chữ số tương ứng Làm lần lượt như vậy cho tới hết số Ví dụ, số

Bo viết lại thành Số , Bo lại viết thành

Yêu cầu: Cho dãy chữ số, hãy cho biết số Bo viết ra tương ứng

Input: Vào từ file LOOKSAY.INP theo quy tắc:

- Dòng đầu tiên là số – số lượng test

- T nhóm dòng tiếp theo, mỗi dòng gồm một dãy chữ số độ dài không quá

1000

Output: ghi ra file LOOKSAY.OUT dòng là kết quả các test tương ứng theo thứ

tự

Ví dụ:

LOOKSAY.INP LOOKSAY.OUT

2

122344111

1111111111

1122132431

101

Ý tưởng tham khảo:

Khởi tạo i: = 0;

(1) Nếu i >= |S| dừng chương trình; nếu không thực hiện lệnh (2)

(2) Tìm vị trí j lớn nhất có thể (j >= i) sao cho tất cả kí tự từ i đến j đều giống nhau Khi đó xuất (j – i + 1) dưới dạng xâu và kèm theo kí tự S[i] ở ngay sau

(3) Gán i:= j + 1 , tiếp tục thực hiện lệnh (1)

Chương trình tham khảo:

#include <bits/stdc++.h>

#define EL cout<<'\n'

#define sz(a) int(a.size())

#define FU(x,a,b) for(int x=int(a);x<=int(b);x++)

#define FD(x,a,b) for(int x=int(a);x>=int(b);x )

#define PROB "LOOKSAY"

using namespace std;

void setIO() {

Trang 14

12

ios_base::sync_with_stdio(0);

cin.tie(0); cout.tie(0);

if(fopen(PROB".inp", "r")){

freopen(PROB".inp", "r",stdin);

freopen(PROB".out", "w",stdout);

}

}

string s;

void readinp(){

cin >> s;

}

string To_string(int x){ /// Hàm chuyển số sang xâu

string res = "";

while (x != 0){

res = res + char(x % 10 + '0');

x = x / 10;

}

reverse(res.begin(), res.end());

return res;

}

void solve(){

int i = 0;

while (i < sz(s)){

int j = i;

char c = s[i];

while (j < sz(s) && s[j] == c)

j++;

j ;

cout << To_string(j - i + 1) << c;

i = j + 1;

}

EL;

}

Trang 15

13

int main(){

setIO();

int t = 1;

cin >> t;

while (t ){

readinp();

solve();

}

}

Bài 5 Dãy hoàn hảo

Cho dãy n phần tử nguyên dương, dãy con của dãy đã cho là dãy các phần tử liên tiếp của dãy đó Độ hoàn hảo của một dãy con là trung bình cộng của dãy con

đó Rõ ràng ta có thể thấy rằng dãy có độ hoàn hảo lớn nhất chính là số lớn nhất trong dãy, như vậy thì quá đơn giản để tìm được dãy con có độ hoàn hảo lớn nhất

Vì vậy ở đây ta chỉ xét những dãy có tổng của các phần tử không nhỏ hơn k

Yêu cầu: Cho n, k và dãy n phần tử, tìm dãy con có độ hoàn hảo lớn nhất

Input: Vào từ file văn bản SEQUENCE.INP gồm:

- Dòng đầu tiên chứa hai số nguyên dương và ( ,

)

- Dòng thứ hai chứa n số nguyên dương a i các phần tử của dãy đã

Output: Ghi ra file văn bản SEQUENCE.OUT một số duy nhất là kết quả tìm

được, làm tròn xuống thành số nguyên

Ví dụ:

SEQUENCE.INP SEQUENCE.OUT

5 6

1 5 2 4 3

3

Ý tưởng tham khảo:

Chặt nhị phân với giá trị trung bình x

Ta có: length * x = sum nên: length >= k/x

Trang 16

14

Đưa bài toán về kiểm tra xem có dãy con liên tiếp độ dài lớn hơn hoặc bằng k/x không?

Chương trình tham khảo:

#include <bits/stdc++.h>

using namespace std;

#define PROB "SEQUENCE"

void Fi(){

freopen(PROB".inp", "r", stdin);

freopen(PROB".out", "w", stdout);

}

typedef long long ll;

const int N = 1e5 + 1;

int a[N], tmp[N], n, k;

bool check(int x){

int minl = k / x + (k % x != 0);

if(minl > n) return false;

for(int i = 1; i <= n; ++i){

tmp[i] = a[i] - x;

}

ll sum = 0, last = 0;

for(int i = 1; i <= minl; ++i){

sum += tmp[i];

}

for(int i = minl + 1; i <= n; ++i){

last += tmp[i - minl];

sum += tmp[i];

if(last < 0){

sum -= last;

last = 0;

}

if(sum >= 0) return true;

}

return false;

}

int main()

Ngày đăng: 21/05/2021, 22:35

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w