#树状数组,高精度#poj 3378 Crazy Thairs

题目

求长度为5的最长上升子序列个数


分析

可以用树状数组实现,然而改了几个月的原因,就是高精度,可以说,不算大,但爆了long long


代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#define rr register
using namespace std;
unsigned n;
unsigned r[51000],s[51000],tmp[51000];
const int inf=1000000000;
struct 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(){
	    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];
signed cmp(int a,int b){return s[a]<s[b];}
inline void deal(){//预处理
	rr int now;
	for(rr int i=0;i<n;++i) tmp[i]=i;
	sort(tmp,tmp+n,cmp);
	r[tmp[0]]=now=1;
	for(rr int i=1;i<n;++i)
		if(s[tmp[i]]==s[tmp[i-1]])
			r[tmp[i]]=now;
		else r[tmp[i]]=++now;
}
inline Bigint query(int i,int val){//求答案
	rr Bigint sum;
	sum.init_();
	if(i<0){
		sum.c=1;
		return sum;
	}
	while(val) sum.add(tree[i][val]),val-=val&-val;
	return sum; 
}
void update(int i,int val){//更新树状数组
	rr Bigint temp=query(i-1,val-1);
	while(val<=n) tree[i][val].add(temp),val+=val&-val;
}
inline signed in(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
int main(){
	while(scanf("%d",&n)==1){
		for(rr int i=0;i<n;++i) s[i]=in();
		if(n<5){//不可能产生
			putchar(48);
			putchar(10);
			continue;
		}
		deal();
		for(rr int i=0;i<5;++i)
			for(rr int j=1;j<=n;++j)//预处理
				tree[i][j].init_();
		for(rr int j=0;j<n;++j)
			for(rr int i=0;i<5;++i)//更新树状数组
				update(i,r[j]);
		query(4,n).print();//输出答案
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值