题目链接 POJ-3378
题意:有N个点,问的是要求组成一个长度为5的上升子序列的组成有多少种?最搞事情的是这道题不用取模!(所以,是一定会爆long long的)。
首先,很容易想到一点就是我们可以开一个dp[maxN][5],表示的是“dp[i][j]当第i个作为这5层中的第j层的时候的组成可能性”。所以,很容易推导的一个dp方程就是
有了这个方程之后,问题就好办了,很容易发现这就是一个开5个树状数组(你要是实在要省,可以开4个)来维护一个前缀和的事情了,我们要统计的答案就是前面所有的小于a[i]的值的作为层j-1时候的答案合计。
好了,问题就这样迎刃而解了?
没有这么简单,这道题的精髓就在于会爆long long,并且还卡了内存,所以用点黑科技吧,之前,高精度的每一位都表示的是0~9中的数,现在不一样了,每一位表示0~99999999(8个9)也就是1e9个数。这样我们就可以将原来的内存需求降到原先的九分之一了。
但是这个的输出可没有那么的简单了,因为可能这一位有前导零啊,所以,我们还是要自定义输出一下,注意一下这个细节。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5e4 + 7;
const ll Base = 1e9;
int N, a[maxN], Lsan[maxN], _UP;
struct Big_Num
{
int len;
ll num[7];
Big_Num() { memset(num, 0, sizeof(num)); len = 0; }
friend Big_Num operator + (Big_Num e1, Big_Num e2)
{
Big_Num ans;
ans.len = max(e1.len, e2.len);
for(int i=0; i<ans.len; i++)
{
ans.num[i] = ans.num[i] + e1.num[i] + e2.num[i];
if(ans.num[i] >= Base)
{
ans.num[i] -= Base;
ans.num[i + 1]++;
if(i + 1 == ans.len) ans.len++;
}
}
return ans;
}
inline void print()
{
if(!len) printf("0");
else
{
printf("%lld", num[len - 1]);
for(int i=len - 2; i>=0; i--) for(int j=Base / 10; j; j/=10) { printf("%lld", num[i]/j); num[i] %= j; }
}
printf("\n");
}
} ans;
struct BIT_TREE
{
Big_Num tree[maxN];
inline void update(int x, Big_Num val)
{
while(x <= _UP)
{
tree[x] = tree[x] + val;
x += lowbit(x);
}
}
inline Big_Num query(int x)
{
Big_Num sum;
while(x)
{
sum = sum + tree[x];
x -= lowbit(x);
}
return sum;
}
} t[5];
int main()
{
Big_Num One, tmp; One.len = 1; One.num[0] = 1;
while(scanf("%d", &N) != EOF)
{
ans = Big_Num();
for(int i=1; i<=N; i++) { scanf("%d", &a[i]); Lsan[i] = a[i]; }
sort(Lsan + 1, Lsan + N + 1);
_UP = (int)(unique(Lsan + 1, Lsan + N + 1) - Lsan - 1);
for(int i=0; i<5; i++) for(int j=1; j<=_UP; j++) t[i].tree[j] = Big_Num();
for(int i=1; i<=N; i++) a[i] = (int)(lower_bound(Lsan + 1, Lsan + _UP + 1, a[i]) - Lsan);
for(int i=1; i<=N; i++)
{
t[0].update(a[i], One);
for(int j=1; j<5; j++)
{
tmp = t[j - 1].query(a[i] - 1);
t[j].update(a[i], tmp);
}
ans = ans + tmp;
}
ans.print();
}
return 0;
}