POJ 3378 树状数组+DP+离散化+高精度

题意:给你一个序列,求其中长度为5的递增序列的个数(N<=50000)

 

这题的dp的方法挺经典的,方程大家应该都会写(那个N^2的),我就不再赘述,这里巧妙地运用了树状数组求和

c[i][j]表示当前状态时,以j(j是数字,不是下标)为结尾的长度为i的序列个数

 

剩下的就是考验高精度了~1100+ms

 

View Code
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <iostream>
  5 #include <algorithm>
  6 
  7 #define SIZE 10
  8 
  9 using namespace std;
 10 
 11 struct BIGN 
 12 {
 13     int a[SIZE];
 14 };
 15 
 16 inline BIGN operator +(BIGN a,BIGN b)
 17 {
 18     BIGN c;
 19     memset(&c,0,sizeof c);
 20     c.a[0]=max(b.a[0],a.a[0]);
 21     int jin=0;
 22     for(int i=1;i<=c.a[0];i++)
 23     {
 24         jin+=a.a[i]+b.a[i];
 25         c.a[i]=jin%10000;
 26         jin/=10000;
 27     }
 28     if(jin) c.a[++c.a[0]]=jin;
 29     return c;
 30 }
 31 
 32 inline void give(char s[],BIGN &a)
 33 {
 34     memset(&a,0,sizeof a);
 35     int len=strlen(s);
 36     int p[4]={1,10,100,1000};
 37     for(int i=len-1,j=0;i>=0;i--,j=(j+1)&3)
 38     {
 39         if(!j) a.a[0]++;
 40         a.a[a.a[0]]=a.a[a.a[0]]+(s[i]-'0')*p[j];
 41     }
 42 }
 43 
 44 inline void prt(BIGN a)
 45 {
 46     printf("%d",a.a[a.a[0]]);
 47     for(int i=a.a[0]-1;i>=1;i--) printf("%04d",a.a[i]);
 48     puts("");
 49 }
 50 
 51 BIGN c[6][50010],ans;
 52 int n,bh;
 53 
 54 struct BZ
 55 {
 56     int x,h,id;
 57 }bz[50010];
 58 
 59 void read()
 60 {
 61     for(int i=1;i<=n;i++)
 62     {
 63         scanf("%d",&bz[i].x);
 64         bz[i].id=i;
 65     }    
 66 }
 67 
 68 inline bool cmp_x(const BZ &a,const BZ &b)
 69 {
 70     return a.x<b.x;
 71 }
 72 
 73 inline bool cmp_id(const BZ &a,const BZ &b)
 74 {
 75     return a.id<b.id;
 76 }
 77 
 78 inline int lowbit(int x)
 79 {
 80     return x&-x;
 81 }
 82 
 83 void lsh()
 84 {
 85     sort(bz+1,bz+1+n,cmp_x);
 86     bz[1].h=2; bh=2;
 87     for(int i=2;i<=n;i++)
 88     {
 89         if(bz[i].x!=bz[i-1].x) bz[i].h=++bh;
 90         else bz[i].h=bh;
 91     }
 92     sort(bz+1,bz+1+n,cmp_id);
 93 }
 94 
 95 inline BIGN getsum(int p,int num)
 96 {
 97     BIGN rt;
 98     give("0",rt);
 99     while(num)
100     {
101         rt=rt+c[p][num];
102         num-=lowbit(num);
103     }
104     return rt;
105 } 
106 
107 inline void updata(int p,int q,BIGN sy)
108 {
109     while(q<=bh)
110     {
111         c[p][q]=c[p][q]+sy;
112         q+=lowbit(q);
113     }
114 }
115 
116 void go()
117 {
118     BIGN one,tmp; give("1",one); give("0",ans);
119     for(int i=0;i<=bh;i++)
120         for(int j=1;j<=5;j++)
121             give("0",c[j][i]);
122     for(int i=1;i<=n;i++) 
123     {
124         updata(1,bz[i].h,one);
125         for(int j=2;j<=5;j++)
126         {
127             tmp=getsum(j-1,bz[i].h-1);
128             updata(j,bz[i].h,tmp);
129         }
130     }
131     ans=getsum(5,bh);
132     prt(ans);
133 }
134 
135 int main()
136 {
137     while(scanf("%d",&n)!=EOF)
138     {
139         read();
140         lsh();
141         go();
142     }
143     return 0;
144 }

 

发现数组开大了,一直tle,搞了半天才AC。。。

posted @ 2012-10-02 21:07  proverbs  阅读(301)  评论(0编辑  收藏  举报