POJ_3378
如果设f[i][j]表示第i个数选a[j]时的方案数,那么f[i][j]就等于所有满足a[k]<a[j]的f[i-1][k]之和,为了能够快速的求出这个和,可以在循环i-1的时候就将所有的f[i-1][k]放到线段树、树状数组或者平衡树上去即可。如果用线段树或者树状数组统计的话,需要将a[]的值离散化。
此外,在计算中间结果时5000^4是不会超long long的,但是最后合并的时候需要用到高精度加法。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXD 50010
int N, T, node, left[MAXD], right[MAXD], a[MAXD], key[MAXD], size[MAXD];
long long int sum[MAXD], num[MAXD], wa[MAXD], wb[MAXD], *f, *g;
struct BigInteger
{
int a[30];
void init(long long int n)
{
int i;
for(i = 0; i < 30; i ++)
{
a[i] = n % 10;
n /= 10;
}
}
BigInteger add(BigInteger &b)
{
int i, s, c = 0;
BigInteger ans;
for(i = 0; i < 30; i ++)
{
s = a[i] + b.a[i] + c;
ans.a[i] = s % 10;
c = s / 10;
}
return ans;
}
void print()
{
int i;
for(i = 29; i > 0; i --)
if(a[i])
break;
for(; i >= 0; i --)
printf("%d", a[i]);
printf("\n");
}
};
void leftrotate(int &T)
{
int k = right[T];
right[T] = left[k];
left[k] = T;
size[k] = size[T];
size[T] = size[left[T]] + size[right[T]] + 1;
sum[k] = sum[T];
sum[T] = sum[left[T]] + sum[right[T]] + num[T];
T = k;
}
void rightrotate(int &T)
{
int k = left[T];
left[T] = right[k];
right[k] = T;
size[k] = size[T];
size[T] = size[left[T]] + size[right[T]] + 1;
sum[k] = sum[T];
sum[T] = sum[left[T]] + sum[right[T]] + num[T];
T = k;
}
void maintain(int &T, int flag)
{
if(flag == 0)
{
if(size[left[left[T]]] > size[right[T]])
rightrotate(T);
else if(size[right[left[T]]] > size[right[T]])
leftrotate(left[T]), rightrotate(T);
else
return ;
}
else
{
if(size[right[right[T]]] > size[left[T]])
leftrotate(T);
else if(size[left[right[T]]] > size[left[T]])
rightrotate(right[T]), leftrotate(T);
else
return ;
}
maintain(left[T], 0);
maintain(right[T], 1);
maintain(T, 0);
maintain(T, 1);
}
void init()
{
int i;
for(i = 1; i <= N; i ++)
scanf("%d", &a[i]);
}
long long int getsum(int &T, int v)
{
if(T == 0)
return 0;
if(v <= key[T])
return getsum(left[T], v);
else
return getsum(right[T], v) + sum[left[T]] + num[T];
}
void newnode(int &T, long long int n, int v)
{
T = ++ node;
key[T] = v;
size[T] = 1;
sum[T] = num[T] = n;
left[T] = right[T] = 0;
}
void Insert(int &T, long long int n, int v)
{
if(T == 0)
{
newnode(T, n, v);
return ;
}
++ size[T];
sum[T] += n;
if(v < key[T])
Insert(left[T], n, v);
else
Insert(right[T], n, v);
maintain(T, v >= key[T]);
}
void solve()
{
int i, j, k;
long long int *t;
BigInteger ans, x;
f = wa, g = wb;
for(i = 1; i <= N; i ++)
g[i] = 1;
for(i = 2; i <= 5; i ++)
{
T = node = size[0] = left[0] = right[0] = 0;
for(j = 1; j <= N; j ++)
{
f[j] = getsum(T, a[j]);
Insert(T, g[j], a[j]);
}
t = f, f = g, g = t;
}
ans.init(0);
for(i = 1; i <= N; i ++)
{
x.init(g[i]);
ans = ans.add(x);
}
ans.print();
}
int main()
{
while(scanf("%d", &N) == 1)
{
init();
solve();
}
return 0;
}