【POJ】3378 Crazy Thairs(树状数组+dp+高精)

题目

传送门:QWQ

分析

题意:给个数列,求有多少五元上升组

考虑简化一下问题:如果题目求二元上升组怎么做。

仿照一下逆序对,用树状数组维护一下就ok了。

三元怎么做呢?

把二元的拓展一位就可以了,即把第三个也扔进树状数组

所以这题就渐渐明朗了:

用$ dp[i][x] $表示以$ A[x] $结尾的$ x $元上升组有多少个

那么:

$ dp[i][x]=sum_{j=1}^{i-1} dp[j][x-1] (A[j]<A[i]) $

其中 $ dp[i][1]=1 $

因为多了一位大的就加了一位嘛

但这个看起来是$ O(n^2) $的,肯定要凉,所以扔进树状数组优化一下。

对了,这题还要离散化和高精度 

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=50010,N = 50010, Base = 10000000;
typedef long long LL; 
class BigNum { 
public:  
    int num[7], len;  
    BigNum():len(0) {}  
    BigNum(int n):len(0) {   for( ; n > 0; n /= Base) num[len++] = n%Base;   }  
    BigNum Bigvalueof(LL n) {  
        len = 0;   while(n) {   num[len++] = n%Base;   n /= Base;   }  
        return *this;  
    }  
    BigNum operator + (const BigNum& b) {   
        BigNum c;   int i, carry = 0;  
        for(i = 0; i < this->len || i < b.len || carry > 0; ++i) {  
            if(i < this->len)   carry += this->num[i];  
            if(i < b.len)   carry += b.num[i];  
            c.num[i] = carry%Base;   carry /= Base;  
        }  
        c.len = i;   return c;  
    } 
    BigNum operator += (const BigNum& b) {  *this = *this + b;   return *this;   }  
    void Print() {  
        if(len == 0)    {puts("0"); return ;}  
        printf("%d", num[len - 1]);  
        for(int i = len - 2; i >= 0; --i) 
            for(int j = Base/10; j > 0; j /= 10) 
                printf("%d", num[i]/j%10);  
        puts("");  
    }  
};
typedef BigNum bign;
int n;
bign sum[maxn][8]; 
struct Node{
    int v,pos;
    bool operator < (const Node& a) const{ return v<a.v; }
}a[maxn];
void add(int x,int e,bign a){for(;x<=n;x+=x&-x)sum[x][e]+=a;}
bign summ(int x,int e){bign ans;for(;x>0;x-=x&-x)ans+=sum[x][e];return ans;}
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){scanf("%d",&a[i].v);a[i].pos=i;}
        sort(a+1,a+1+n); memset(sum,0,sizeof(sum));
        int cnt=0;
        bign ans=0;
        for(int i=1;i<=n;i++){
            add(a[i].pos,1,1);
            for(int j=2;j<=5;j++){
                add(a[i].pos,j,summ(a[i].pos-1,j-1));
            }
        }
        summ(n,5).Print();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/noblex/p/9229175.html