题目:http://poj.org/problem?id=3378
题意:求满足下列要求的5元组的个数
1. 1 ≤ i < j < k < l < m ≤ N
2. Ai < Aj < Ak < Al < Am
学习了一种机智的做法,在范围超longlong不大的时候可以使用2个longlong来避免写高精度
首先我们对数据进行离散化
设dp[i][j]为以 a[j] 结尾的上升 i 序列 1<=i<=5
dp[i][j]=sum{dp[i-1][k]} a[k]<a[j] 1<=k<j
然后我们可以用树状数组来维护sum
add(i,a[j],sum(i-1,a[j]-1))
因为最后一维是答案且不需要查询,而且只有这一维的大小会爆longlong,所以我们可以用2个longlong来存放答案
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const int N=5e4+5; const ll base=1e15; struct p { int x,y; bool operator <(const p &t) const { return x<t.x; } }; p tem[N]; int a[N]; ll s[5][N],ans1,ans2; void add(int k,int i,ll x) { while(i<N) { s[k][i]+=x; i+=i&-i; } } ll sum(int k,int i) { ll t=0; while(i>0) { t+=s[k][i]; i-=i&-i; } return t; } int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) { scanf("%d",&tem[i].x); tem[i].y=i; } sort(tem+1,tem+1+n); memset(s,0,sizeof(s)); a[tem[1].y]=1; int cnt=1; for(int i=2;i<=n;i++) if (tem[i].x==tem[i-1].x) a[tem[i].y]=cnt; else a[tem[i].y]=++cnt; ans1=ans2=0; for(int i=1;i<=n;i++) { add(1,a[i],1); for(int j=2;j<=4;j++) add(j,a[i],sum(j-1,a[i]-1)); ans1+=sum(4,a[i]-1); ans2+=ans1/base; ans1%=base; } if (ans2) printf("%lld",ans2); printf("%lld ",ans1); } return 0; }