poj3378 Crazy Thairs 高精度,树状数组
为了比赛,准备整理一套高精模板。
虽然赵老师会Java,但是这玩意总是莫名不靠谱。
本题,给一个有序集合,问原序满足从小到大而且值满足从小到大的五元组有多少个。
按值建树状数组。每个点保存5个值,代表以当前节点为最后一个元素,长度为i(1<=i<=5)的集合有多少个。
然后按原数组序从左到右插入。每次查找比当前点值小的,长度为i-1的有集合总数,则当前点长度为i的集合数就是该值。
结果会超出long long,所以需要高精度。
为了比赛,准备整理一套高精模板。
虽然赵老师会Java,但是这玩意总是莫名不靠谱。
本题,给一个有序集合,问原序满足从小到大而且值满足从小到大的五元组有多少个。
按值建树状数组。每个点保存5个值,代表以当前节点为最后一个元素,长度为i(1<=i<=5)的集合有多少个。
然后按原数组序从左到右插入。每次查找比当前点值小的,长度为i-1的有集合总数,则当前点长度为i的集合数就是该值。
结果会超出long long,所以需要高精度。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define lowbit(x) (x&(-x))
#define NN 51000
#define maxl 10
struct bign{
int l,s[maxl];
bign(){l=0;memset(s,0,sizeof(s));}
void init(){l=0;memset(s,0,sizeof(s));}
bign operator =(int a){
this->init();
while(a){
s[l++]=a%10000;
a=a/10000;
}
while(l&&s[l]==0) --l;
return *this;
}
bign operator +(bign b){
bign ret;
int tl=l>b.l?l:b.l,i,c=0;
for(i=0;i<=tl;++i){
ret.s[i]=s[i]+b.s[i]+c;
c=ret.s[i]/10000;
ret.s[i]%=10000;
}
if (c) ret.s[++tl]=c;
ret.l=tl;
return ret;
}
bign operator +=(bign b){
*this=*this+b;
return *this;
}
void output(){
int i;
printf("%d",s[l]);
for(i=l-1;i>=0;--i){
printf("%04d",s[i]);
}
printf("\n");
}
};
bign c[6][NN];
int a[NN],b[NN];
int n,p;
void insert(int x,int pos,bign val){
while(pos<=p){
c[x][pos]+=val;
pos+=lowbit(pos);
}
}
bign query(int x,int pos){
bign ret;
ret=0;
while(pos){
ret+=c[x][pos];
pos-=lowbit(pos);
}
return ret;
}
int search(int val){
int l=1,r=p,m;
while(l<=r){
m=(l+r)/2;
if (b[m]==val) return m;
else if (b[m]<val) {
l=m+1;
}
else r=m-1;
}
}
int main(){
int i,j,pos;
bign tmp,ans;
while(scanf("%d",&n)!=EOF){
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
p=1;
for(i=2;i<=n;++i){
if (b[i]!=b[i-1]) b[++p]=b[i];
}
for(i=1;i<=p;++i){
for(j=1;j<=5;++j){
c[j][i]=0;
}
}
for(i=1;i<=n;++i){
pos=search(a[i]);
bign bg;
bg=1;
insert(1,pos,bg);
for(j=2;j<=5;++j){
tmp=query(j-1,pos-1);
insert(j,pos,tmp);
}
}
ans=query(5,p);
ans.output();
}
return 0;
}