pku 3378樹狀數組解法:
看到題目,我們首先應該想到的是求:在一個數組裏前n-1個數有多少個比第n個數小。
對於這個問題,我先將這個數組離散化---就是得到第n個數是第幾大(或小)的數,然後建立樹狀
數組,s[i]爲第i大的數前面的所有的數的個數(包括第i大的數),這樣說或許不好理解,但是,
我解釋一下以下的語句就簡單多了:(前提是你已經對樹狀數組有所瞭解)
for(int i=1;i<=N;i++){ 此條語句就是對每一個數進行統計(排序前)
increase(status[i],1); 如果統計到k,則前k-1個數的分別應該在s中的位置就已經
確定了,故:
ans[i] = sum(status[i]-1); 答案就是,比當前數在整個數組中的位置小一的和即s[status[i]-1];
}
有了以上一個題目作基礎,再看次題目是不是有一些眉目了,對了,求三元應該在二元的基礎上,以此類推便可以得到五元的
數目了,解釋:
因爲每一個數在整個數組中的相對位置是不變的,說以比方說對於數組 4 5 6 1 2 3 7 8,對於6有兩個數4和5可以同
6組成二元組,如果按照統計二元組的方法統計三元組,那麼循環統計到7的時候,其前面必然可以找到6,而此時對於
7,其總量就應該增加在二元組結果中6的答案數,同樣應該增加5(1)、3(2)、2(1)的答案數即7的三元組答案是
1+2+1+2 = 6.以此類推可的到最終答案,不在贅述。
顯然使用樹狀數組的時間複雜度爲O(nlgn)
參考程序:(注意要用高精度實現加法)
programme:pku 3378
#include<iostream>
#include<algorithm>
using namespace std;
#define BUFSIZE 60000
#define INT __int64
struct Num{
int id;
int key;
};
Num table[BUFSIZE];
int status[BUFSIZE];
int N;
INT S[BUFSIZE];
INT ans[BUFSIZE];
INT temp[BUFSIZE];
struct hp{
int s[30];
int n;
};
hp Shp[BUFSIZE];
hp anshp[BUFSIZE];
hp temphp[BUFSIZE];
bool comp(Num a,Num b)
{
return a.key<b.key;
}
int init()
{
for(int i=1;i<=N;i++){
scanf("%d",&table[i].key);
table[i].id = i;
}
sort(table+1,table+N+1,comp);
int t = 0,p = -1;
for(int i=1;i<=N;i++){
if(table[i].key>p){
t++;
p = table[i].key;
}
status[table[i].id] = t;
}
}
int lowbit(int x)
{
return x&(x^(x-1));
}
void increase(int n,INT v)
{
for(int i=n;i<=N;i+=lowbit(i))
S[i] += v;
}
INT sum(int n)
{
INT t = 0;
for(int i=n;i>0;i-=lowbit(i))
t += S[i];
return t;
}
void add(hp &a,hp b)
{
int c = 0;
if(a.n>b.n){
for(int j=0;j<b.n;j++){
a.s[j] += c+b.s[j];
c = a.s[j]/10;
a.s[j] %= 10;
}
for(int j=b.n;j<a.n;j++){
a.s[j] += c;
c = a.s[j]/10;
a.s[j] %= 10;
}
if(c>0){
a.s[a.n] = c;
a.n++;
}
}else {
for(int j=0;j<a.n;j++){
a.s[j] += c+b.s[j];
c = a.s[j]/10;
a.s[j] %= 10;
}
for(int j=a.n;j<b.n;j++){
a.s[j] = c+b.s[j];
c = a.s[j]/10;
a.s[j] %= 10;
}
if(c>0){
a.s[b.n] = c;
a.n = b.n+1;
}else
a.n = b.n;
}
}
void increasehp(int n,hp v)
{
for(int i=n;i<=N;i+=lowbit(i))
add(Shp[i],v);
}
void sumhp(int n,hp &t)
{
t.n = 1;
t.s[0] = 0;
for(int i=n;i>0;i-=lowbit(i))
add(t,Shp[i]);
}
void copy(hp &a, hp b)
{
a.n = b.n;
for(int i=0;i<b.n;i++)
a.s[i] = b.s[i];
}
int main()
{
while(scanf("%d",&N)!=EOF){
init();
fill_n(temp,N+1,1);
for(int k=1;k<3;k++){
fill_n(S,N+1,0);
for(int i=1;i<=N;i++){
increase(status[i],temp[i]);
ans[i] = sum(status[i]-1);
}
for(int i=1;i<=N;i++)
temp[i] = ans[i];
}
for(int i=1;i<=N;i++){
temphp[i].n = 0;
while(ans[i]!=0){
temphp[i].s[temphp[i].n++] = ans[i]%10;
ans[i] /= 10;
}
}
for(int k=1;k<3;k++){
for(int i=1;i<=N;i++)
Shp[i].n = 1,Shp[i].s[0] = 0;
for(int i=1;i<=N;i++){
increasehp(status[i],temphp[i]);
sumhp(status[i]-1,anshp[i]);
}
for(int i=1;i<=N;i++)
copy(temphp[i],anshp[i]);
}
hp sum;
sum.n = 1,sum.s[0] = 0;
for(int i=1;i<=N;i++)
add(sum,anshp[i]);
for(int i=sum.n-1;i>=0;i--)
printf("%d",sum.s[i]);
printf("/n");
}
return 0;
}