UESTC 地址 : http://acm.uestc.edu.cn/problem.php?pid=1460
POJ 地址 : http://poj.org/problem?id=3378
经典题目。
方法 :树状数组+dp+离散化+大整数
时间复杂度:O(5*n*2*logn)
因为数据太大,不能作为下标使用。
于是离散化。
然后利用DP的思想,树状数组的方法(五个树状数组),逐步把 长度为1、2、3、4、5的上升序列个数记录。
当记录长度为2、3、4、5时,均用到上一长度总数。
结果太大,爆long long ,没有想到。WA了很久,网上查了一下,才知道。
后来利用Bigint解决。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int r[51000],s[51000],tmp[51000];
const int inf=1000000000;
struct Bigint{ // 结果爆 longlong,所以用 Bigint
int a,b,c;
void add(Bigint y){
c+=y.c;
if(c>=inf)
c-=inf,b++;
b+=y.b;
if(b>=inf)
b-=inf,a++;
a+=y.a;
}
void print(){ // 差点栽在这里,用于存储后半节大整数的数,可能需要前导0
if(a) printf("%d%09d%09d\n",a,b,c);
else if(b) printf("%d%09d\n",b,c);
else printf("%d\n",c);
}
void init_(){
a=b=c=0;
}
}tree[5][51000];
int cmp(int a,int b){
return s[a]<s[b];
}
void deal(){ // 离散化:可以用于数组下标太大,或者有浮点数时。
int i,now;
for(i=0;i<n;i++) tmp[i]=i;
sort(tmp,tmp+n,cmp);
r[tmp[0]]=now=1;
for(i=1;i<n;i++)
if(s[tmp[i]]==s[tmp[i-1]])
r[tmp[i]]=now;
else r[tmp[i]]=++now;
}
Bigint query(int i,int val){
Bigint sum;
sum.init_();
if(i<0){
sum.c=1;
return sum;
}
while(val>0){
sum.add(tree[i][val]);
val-=val&-val;
}
return sum;
}
void update(int i,int val){
Bigint temp;
temp = query(i-1,val-1);
while(val<=n){
tree[i][val].add(temp);
val+=val&-val;
}
}
int main(){
int i,j;
while(cin>>n){
for(i=0;i<n;i++)
cin>>s[i];
if(n<5){
cout<<"0"<<endl;
continue;
}
deal();
for(i=0;i<5;i++)
for(j=1;j<=n;j++)
tree[i][j].init_();
for(j=0;j<n;j++)
for(i=0;i<5;i++)
update(i,r[j]);
query(4,n).print();
}
return 0;
}