KHỐi thi tập thể Bài 1: Triangle



tải về 55.95 Kb.
Chuyển đổi dữ liệu07.01.2018
Kích55.95 Kb.
KHỐI THI TẬP THỂ

Bài 1: Triangle

Đây là bài tương đối dễ, chỉ cần kiểm tra một trong các khả năng a*a=b*b+c*c

b*b=a*a+c*c

c*c=a*a+b*b

Kiểu dữ liệu dùng để khai báo 3 số a,b,c là int. Không có lưu ý gì đặc biệt trong bài này.

Bài 2: Number

Đây cũng là một bài khá đơn giản. Tuy nhiên cần phải lưu ý đến điều kiện N<=10^200. Với các kiểu dữ liệu số nguyên trên C/C++ chúng ta không thể lưu trữ được số lớn đến 10^200. Để biểu diễn số N, trong bài này cần sử dụng xâu ký tự. Việc tiếp theo là cần kiểm tra xem xâu ký tự đó có đối xứng hay không. Chương trình chỉ đơn giản như sau:

int ktra(char* s){

int l=strlen(s);

for(int i=0;i<=l/2;i++)

if(s[i]!=s[l-1-i]) return 0;

return 1;

}

void main(){



char s[300];

scanf("%s",s);

printf("%d",ktra(s));

}

Với bài này, có thể không cần dùng hàm phụ trợ, việc kiểm tra tính đối xứng có thể đưa luôn vào hàm main()



Bài 3: Conflict

Bài này chúng ta cần phải giải quyết hai bài toán con: tìm các chữ số của một số nguyên và tìm ước số chung lớn nhất của hai số nguyên. Hai bài toán này là những bài toán cơ bản và không có gì khó

Để giải bài toán con thứ nhất, ta dùng mảng số nguyên để lưu trữ các chữ số. Chương trình như sau:

int uscln(int a, int b){

if (a==0) return b;

if(b==0) return a;

if (a>b) return uscln(a%b,b);

else return uscln(a, b%a);

}

void main(){



int N,temp,i,so_chu_so=0;

int a[10];

scanf("%d",&N);

//Tìm các chữ số của N:

temp=N;

while(temp>0){



a[so_chu_so]=temp%10;

temp=temp/10;

so_chu_so++;

}

//Tính số đảo ngược của N và lưu vào temp:



temp=0;

for(i=0;i

temp=temp*10+a[i];

//Đưa ra kết quả

printf("%d",(uscln(N,temp)==1));

}

Lưu ý: Khi tìm USCLN cần giảm tham số bằng cách a=a%b hoặc b=b%a. Nếu giảm tham số bằng cách a=a-b hoặc b=b-a thì sẽ gây tràn stack khi N lớn do số lần đệ quy quá nhiều.



Bài 4: SUBARR

Để giải bài này đầu tiên có thể sử dụng 2 vòng lặp lồng nhau, vòng bên trong tìm tổng lớn nhất các phần tử liên tiếp bắt đầu từ chỉ số i, vòng bên ngoài tìm tổng lớn nhất trong các tổng tìm được. Theo cách này độ phức tạp sẽ là O(n^3).

Cách khác:

Gọi mảng b là mảng như sau:

b[i]=a[0]+a[1]+…+a[i], 0<=i<=n-1;

Việc tiếp theo là cần tìm giá trị lớn nhất trong b[0], b[1],…,b[n-1], b[j]-b[i] (với mọi n-1>=j>i>=0).

Độ phức tạp theo cách này O(n^2).

Bài 5: PERMUTATION

Đây cũng là bài toán cơ bản. Chỉ cần biết thuật toán liệt kê các hoán vị.

Gọi (a1,a2,a3...an) là hoán vị được cho

Nếu hoán vị được cho là (n,n-1,…,1) thì đưa ra 0. Kiểm tra điều này rất đơn giản: duyệt xem tất cả ai có bằng n+1-i hay không (i=1,2,..,n)

Nếu a=(a1,a2,a3...an) là môt hoán vị chưa phải là hoàn vị cuối cùng thì hoán vị kế tiếp của a được xác định như sau:

-Tìm từ phải qua trái trong hoán vị đang có chỉ số k đầu tiên thỏa mãn ak

-Trong các phần tử ở bên phải của ak và lớn hơn ak tìm phần tử nhỏ nhất ai.

-Đổi chỗ hai phần tử ak và ai.

-Lật ngược đoạn các phần tử từ ak+1 đến an.

VD với n=6 và hoán vị đang xét là a=(3,6,2,5,4,1) thì chỉ số k cần tìm là k=3 (vì a3=2

Ngoài cách tự viết chương trình theo thuật toán trên, có thể sử dụng hàm next_permutation() trong thư viện của STL.
Bài 6: Func

Ý tưởng giải bài này dựa trên phương pháp quy hoạch động. Giả sử đối với dãy a1,a2,…,a[n-1] đã tìm được 3 chỉ số 1<=i’

Để cài đặt, trong chương trình ta khai báo 3 biến toàn cục int i,j,k;

Ban đầu với dãy a1,a2,a3: hiển nhiên i=1, j=2, k=3.

Sau đó lần lượt tính i,j,k cho các dãy tiếp theo:

for(s=4;s<=n;s++){

f1=a[i]+3*a[j]+5*a[k];

f2=a[i]+3*a[j]+5*a[s];

f3=a[j]+3*a[k]+5*a[s];

f4=a[i]+3*a[k]+5*a[s];

tính fm=max(f1,f2,f3,f4);

nếu fm==f1 continue;

nếu fm==f2 {k=s;continue;}

nếu fm==f3 {i=j;j=k;k=s;continue;}

nếu fm==f4 {j=k;k=s;continue;}

}

Đưa ra tổng a[i]+3*a[j]+5*a[k];



Độ phức tạp O(n-3). Nếu sử dụng duyệt vét cạn thì độ phức tạp là O(n^3).

KHỐI CÁ NHÂN CHUYÊN TIN

Bài 1: Squared

Bài này tương đối đơn giản, chỉ cần sử dụng một vòng for

void main(){

for(int i=0;i<100;i++)

if (i*i==N) {cout<<"YES";return;}

cout<<"NO";

}

Lưu ý: Không nên dùng hàm sqrt(x) để tính căn bậc 2 vì hàm này sử dụng chuỗi để tính (tốc độ kém hơn).



Bài 2: Max_Div

int uscln(int a, int b){

if (a==0) return b;

if(b==0) return a;

if (a>b) return uscln(a%b,b);

else return uscln(a, b%a);

}

Bài 3: Stairs

Đây là bài quy hoạch động điển hình. Cần tìm số cách biểu diễn số nguyên dương n thành tổng một số số nguyên dương n=a[1]+a[2]+…+a[t] với 1<=t<=n và 1<=a[1]

Gọi F(n,k) là hàm tính số lượng cách biểu diễn n thành tổng các số như trên với a[t]<=k (1<=k<=n). Khi đó a[t] chỉ có thể có hai khả năng a[t]=k và a[t]

Với a[t]=k thì a[1]+a[2]+…+a[t-1]=n-a[t]=n-k. (1)

Vì a[t-1]

Suy ra số cách biểu diễn n thành tổng các số với số cuối cùng bằng k sẽ là F(n-k,k-1) (theo (1) và (2)). (3)

Với a[t]

Từ (3) và (4) nhận được F(n,k)=F(n,k-1)+F(n-k,k-1)

Dễ dàng nhận thấy

F(0,k) = 1

F(0,0)=1

F(n,0) =0 với n>0.


Kết quả cần tìm là F(n,n).

Bài 4: BEE

Bài này liên quan đến hình học vector. Ta quy định ô lục giác xuất phát là gốc tọa độ O trong hệ tọa độ OXYZ. Ký hiệu nx,ny,nz là 3 vector đơn vị theo hướng 3 trục X,Y,Z. Theo công thức cộng vector và tính chất của 3 trục X,Y,Z có thể thấy rằng

nx+nz=ny (1)

Đường đi của con ong từ gốc tọa độ đến ô lục giác có mật có thể biểu diễn dưới dạng

A*nx+B*ny+C*nz (2)

Với ví dụ cho trong bài thì để đi đến ô có mật con ong cần đi theo đường

-2*nz+3*ny+3*nz-nz=-nx+3*ny+nz, nghĩa là với ví dụ đã cho thì A=-1,B=3,C=1.

Để tìm 3 hệ số A,B,C ta đọc từ file BEE.IN, giả sử f là biến file:

char c;

int d,A,B,C;



A=B=C=0;

fscanf(f,”%d”,&N);//Đọc số lần dịch chuyển

for (int i=0;i

fscanf(f,”%c%d”, &c,&d);//đọc hướng và độ dịch theo hướng

if (c==’X’) A=A+d;

if (c==’Y’) B=B+d;

if (c==’Z’) C=C+d;

}

fclose(f);



Sau khi đã tìm được 3 số A,B,C thì có thể thấy rằng muốn đi về ô xuất phát (gốc tọa độ) thì con ong có thể đi theo đường là –A*nx-B*ny-C*nz. Tuy nhiên 3 vector nx,ny,nz theo (1) không độc lập tuyến tính nên để đi về gốc tọa độ, con ong chỉ cần di chuyển theo 2 phương là đủ.

Theo (1) thì

A*nx+B*ny+C*nz=(A+B)*nx+(B+C)*nz=(A-C)*nx+(B+C)*ny

=(B+A)*ny+(C-A)*nz.

Và con đường ngắn nhất cần phải tìm là

min(|A+B|+|B+C|,|A-C|+|B+C|,|B+A|+|C-A|)

Trong ví dụ đã cho (A=-1,B=3,C=1) con đường ngắn nhất là

min(2+4,2+4,2+2)=4.



KHỐI CÁ NHÂN KHÔNG CHUYÊN TIN

Bài 1: Circle

Bài này khá đơn giản, chỉ cần so sánh (xm-x)*(xm-x)+(ym-y)*(ym-y) và r*r.

Nếu (xm-x)*(xm-x)+(ym-y)*(ym-y)> r*r thì M nằm ngoài đường tròn

Nếu (xm-x)*(xm-x)+(ym-y)*(ym-y) = = r*r thì M nằm trên đường tròn

Nếu (xm-x)*(xm-x)+(ym-y)*(ym-y)< r*r thì M nằm trong đường tròn
Tuy nhiên cần lưu ý sử dụng kiểu dữ liệu để biểu diễn các tham số đầu vào xm,ym,x,y,r. Nếu sử dụng kiểu int thì (xm-x)^2+(ym-y)^2 hay r^2 có thể vượt ra ngoài khoảng cho phép của số int và đem lại kết quả thực tế là số âm, hệ quả là đưa ra kết quả sai (ví dụ x=-999999, y=-999999, r=999999, xm=999999, ym=999999). Vì vậy kiểu dữ liệu cần dùng để khai báo xm,ym,x,y,r phải là float hoặc double.

Nếu vẫn khai báo các tham số có kiểu int thì phải sử dụng hàm sqrt để tính khoảng cách từ (xm,ym) đến (x,y). Khi đó cần so sánh

sqrt((float) (xm-x)*(xm-x)+(ym-y)*(ym-y)) và r

Tuy nhiên theo cách này thì sẽ phải tính đến độ chính xác 10^-6, sẽ rắc rối hơn.



Bài 2: Squared

Xem ở trên



Bài 3: Max_Div

Xem ở trên



Bài 4: BEE

Xem ở trên



Người viết

Phan Nguyên Hải


Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2016
được sử dụng cho việc quản lý

    Quê hương