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。。。
没有人能阻止我前进的步伐,除了我自己!