Nguồn đề bài: http://vn.spoj.com/problems/NKINV/
1. Đề bài NKINV spoj
Cho một dãy số a1.. aN. Một nghịch thế là một cặp số u, v sao cho u < v và au > av. Nhiệm vụ của bạn là đếm số nghịch thế.
Dữ liệu
- Dòng đầu ghi số nguyên dương N.
- N dòng sau mỗi dòng ghi một số ai ( 1 ≤ i ≤ N ).
Kết quả
Ghi trên một dòng số M duy nhất là số nghịch thế.
Giới hạn
- 1 ≤ N ≤ 60000
- 1 ≤ ai ≤ 60000
Ví dụ
Dữ liệu: 3 3 1 2 Kết quả 2
2. Hướng dẫn NKINV spoj
Bài này mình sẽ bày cách cho các bạn dùng cây IT để làm:
Vì 1<=ai<=60000 nên ta dùng một mảng it[60001] để đánh dấu sự xuất hiện của các giá trị. it[i]=k tức là trong đoạn ta xét hiện thời, số i đã xuất hiện k lần.
Khởi đầu số nghịch thế bằng 0: ds=0.
Ta xét từ cuối mảng tới đầu mảng, mỗi lần gặp giá trị a[i], ta tính tổng các số trong mảng it từ 1 tới a[i]-1. Tức là tính xem có bao nhiêu số nhỏ hơn số a[i] đã xuất hiện. (Phần này dùng it tổng.) Sau đó cập nhật a[i] vào cây, tăng it[a[i]] lên một đơn vị.
Nếu các bạn chưa hiểu có thể cmt để hỏi thêm. Cảm ơn! 😀
3. Code tham khảo NKINV spoj
#include <bits/stdc++.h> #define maxn 60001 using namespace std; int n; int a[maxn], it[5*maxn]; void update(int r, int k, int l, int u, int v, int val) { if(v<k||l<u) return; if(u<=k&&l<=v){it[r]+=val; return;} int g=(k+l)/2; update(2*r,k,g,u,v,val); update(2*r+1,g+1,l,u,v,val); it[r]=it[2*r]+it[2*r+1]; } int get(int r, int k, int l, int u, int v) { if(v<k||l<u) return 0; if(u<=k&&l<=v) return it[r]; int g=(k+l)/2; int t1=get(2*r,k,g,u,v); int t2=get(2*r+1,g+1,l,u,v); return t1+t2; } int main() { cin>>n; int m=0; for(int i=1; i<=n; i++) { cin>>a[i]; m=max(m, a[i]); } int ds=0; for(int i=n; i>=1; i--) { int t=get(1,1,m,1,a[i]-1); ds=ds+t; update(1,1,m,a[i],a[i],1); } cout<<ds; }
Ad cho em hoi tai sao , vong for o cuoi lai chay tu n den 1 , chu khong phai tu 1 den n vay ?
Em xin cam on
thực ra thì có thể for từ 1 đến n. nhưng mình thích for từ n đến 1 cơ. :)))
thực ra thì có thể for từ 1 đến n. nhưng mình thích for từ n đến 1 cơ. :)))
– Có thể giải thích tại sao mình copy code của bạn nộp ở NTUCoder lại WA test 14 không?.. trong lúc mình nộp ở SPOJ thì 100đ.
có. ntu a[i]<=10^5
bạn giải thích cho mình tại sao phần update (v<k) or (l<u) mà không phải là (v<r) or (l<u) với
ở đây. r là gốc, quản lí các nút trong đoạn từ k đến l. bạn có thể tìm hiểu thêm trong các bài viết về cây IT. cảm ơn bạn.
cảm ơn ad nhiều . code đẹp quá! :))