POJ 3378——Crazy Thairs(树状数组+dp+高精度)数据结构优化的DP

Crazy Thairs

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 6598   Accepted: 1636

Description

These days, Sempr is crazed on one problem named Crazy Thair. Given N (1 ≤ N ≤ 50000) numbers, which  are no more than 109, Crazy Thair is a group of 5 numbers {i, j, k, l, m} satisfying:

1. 1 ≤ i < j < k < l < m  N

2. Ai < Aj < Ak < Al < Am

For example, in the sequence {2, 1, 3, 4, 5, 7, 6},there are four Crazy Thair groups: {1, 3, 4, 5, 6}, {2, 3, 4, 5, 6}, {1, 3, 4, 5, 7} and {2, 3, 4, 5, 7}.

Could you help Sempr to count how many Crazy Thairs in the sequence?

Input

Input contains several test cases. Each test case begins with a line containing a number N, followed by a line containing N numbers.

Output

Output the amount of Crazy Thairs in each sequence.

Sample Input

5
1 2 3 4 5
7
2 1 3 4 5 7 6
7
1 2 3 4 5 6 7

Sample Output

1
4
21

——————————————————分割线————————————————————

题目大意:

给定n个数,求满足

1. 1 ≤ i < j < k < l < m ≤ N

2. Ai < Aj < Ak < Al < Am

的总方案数

思路:

dp[i][j]表示以j为结尾长度为i的序列的方案数,则dp[i][j]=dp[i-1][k],其中a[k]要小于a[j]

因此,要想知道5元组的方案数,就要知道4元组的方案数,4元组又要知道3元组的方案数........当长度为1时,方案数为1

对于统计比a[i]小的元素的个数,用树状数组再简单合适不过了

又对于每个元素的数据范围为10的9次方,而题目给的数的个数为50000个,离散化是必须的

又组合数 C(50000,5)必定超过__int64,所以要用高精度

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define M 50000+10
#define ll long long
#define local1
using namespace std;
int n,ans[50],f[M];
ll c[4][M];
struct node
{
    int x,index;
    bool operator< (const node &A)const
    {
        return x<A.x;
    }
}a[M];
void update(int x,ll v,int k)
{
    for(int i=x;i<=n;i+=i&-i){
        c[k][i]+=v;
    }
}
ll getsum(int x,int k)
{
    ll sum=0;
    for(int i=x;i>0;i-=i&-i){
        sum+=c[k][i];
    }
    return sum;
}
void add(ll s)
{
    int t1[50],t2[50],k=0;
    memset(t1,0,sizeof(t1));memset(t2,0,sizeof(t2));
    while(s>0){
        t2[k++]=s%10;
        s/=10;
    }
    for(int i=0;i<50;++i){
        t1[i]+=t2[i]+ans[i];
        if(t1[i]>=10){
            t1[i+1]=t1[i]/10;
            t1[i]%=10;
        }
        ans[i]=t1[i];
    }
}
int main()
{
#ifdef local
    freopen("in.txt","r",stdin);
    freopen("ou.txt","w",stdout);
#endif // local
    while(scanf("%d",&n)!=EOF){
        memset(c,0,sizeof(c));memset(ans,0,sizeof(ans));
        for(int i=0;i<n;++i){
            scanf("%d",&a[i].x);
            a[i].index=i;
        }
        sort(a,a+n);
        int key=1;f[a[0].index]=1;
        for(int i=1;i<n;++i){
            if(a[i].x>a[i-1].x) f[a[i].index]=++key;
            else f[a[i].index]=key;
        }
        for(int i=0;i<n;++i){
            update(f[i],1,0);
            for(int j=1;j<=3;++j){
                update(f[i],getsum(f[i]-1,j-1),j);
            }
            add(getsum(f[i]-1,3));
        }
        int k=49;
        for(;k>=0;--k){
            if(ans[k]) break;
        }
        for(int i=k;i>=0;--i){
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-11-04 07:43:04

POJ 3378——Crazy Thairs(树状数组+dp+高精度)数据结构优化的DP的相关文章

●POJ 3378 Crazy Thairs

题链: http://poj.org/problem?id=3378 题解: 树状数组维护,高精度. 依次考虑以每个位置结尾可以造成的贡献. 假设当前位置为i,为了达到5个元素的要求,我们需要求出,在序列1-i-1中有多少个合法4元组$(a<b<c<d且A_a<A_b<A_c<A_d)$的最后那个元素是小于$A_i$的$(即为了满足a<b<c<d<i且A_a<A_b<A_c<A_d<A_i)$,求出这种四元组的个数,那么就

hdu 1541/poj 2352:Stars(树状数组,经典题)

Stars Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4052    Accepted Submission(s): 1592 Problem Description Astronomers often examine star maps where stars are represented by points on a plan

POJ 2892 Tunnel Warfare (树状数组+二分)

题目大意: 三个操作 D pos  将pos位置摧毁,让它和周围不相连. Q pos 问和pos 相连的有多少个村庄. R 修复最近摧毁的村庄. 思路分析: 树状数组记录这个区间有多少个1. 如果  [s-e] 有e-s+1个1 的话.那么这个区间是相连的. 这样的话,我们就可以用二分的办法求出与某个位置最大相连的数量. 还有这里二分 while(l<=r) { if(满足) { ans=mid; l=mid+1; } else r=mid-1; } #include <cstdio>

poj 2155 二维树状数组

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17721   Accepted: 6653 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. I

poj 2309 BST 使用树状数组的lowbit

如果领悟了树状数组中的lowbit,这道题就是极其简单的,最底层都是奇数,用lowbit(x)寻找x的父亲,然后x的父亲-1就是最大数 至于lowbit是如何计算的嘛,寻找x的父亲,其实就是x+2^x的二进制末尾0的个数. #include<iostream> #include<stdio.h> using namespace std; typedef long long ll; ll lowbit(int x){ return x&(-x); } int main(){

poj 1195 二维树状数组 及二维树状数组模板

http://poj.org/problem?id=1195 求矩阵和的时候,下标弄错WA了一次... 求矩形(x1,y1) (x2,y2)的sum |sum=sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1) 二维树状数组讲解:http://blog.csdn.net/u011026968/article/details/38532117 二维树状数组模板: /*========================================

POJ 3378 Crazy Thairs(树状数组+DP)

[题目链接] http://poj.org/problem?id=3378 [题目大意] 给出一个序列,求序列中长度等于5的LIS数量. [题解] 我们发现对于每个数长度为k的LIS有dp[k][i][a[i]]=dp[k-1][i-1][0~a[i]-1] 我们用5个树状数组维护不同长度的LIS,递推即可,注意答案超过LL,需要用大数. [代码] #include <cstdio> #include <algorithm> #include <cstring> usi

POJ 2892 Tunnel Warfare [树状数组]

题目链接: http://poj.org/problem?id=2892 题意:一个长度为n的线段,下面m个操作 D x 表示将单元x毁掉 R  表示修复最后毁坏的那个单元 Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0 思路: 这道题是经典的线段树入门题目,由于只是进行单点更新, 不涉及区间更新,用树状数组更简洁. 维护两个树状数组,一个是把所有的1进行维护,一个是把所有的0进行维护. 翻转(炸毁或修复)任何一个单元,同时修改这两个树状数组,仅仅是为了 合并 

poj 2299 Ultra-QuickSort 离散化 + 树状数组

题目链接:http://poj.org/problem?id=2299 离散化 + 树状数组 教科书例题般的题目 #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <vector> #include <stack> #include <set> #include