hdu2227 && hdu3450 【树状数组优化dp】
hdu2227
树状数组的一个经典应用。
容易得到dp方程,dp[pos]表示前pos项里以a[pos]结尾的非降子序列的个数。
则有dp[pos]=sum( dp[i] , 1<= i <pos && a[i]<=a[pos] ) + 1。
复杂度为O(n^2),Time Limit Exceeded!!!
观察到a[i]<=a[pos] , 我们对原序列a从小到大排序,得到新的序列d,对d进行dp。
此时dp[pos]=sum(dp[i],1<=i<pos && d[i]的原序在d[pos]的原序之前 ) + 1。
对于元素d[pos] , d[1],...,d[pos-1]都<=d[pos],但是这些元素的原序可能在d[i]之后,而dp[i]只能依赖原序在d[i]之前的值来更新。
怎么解决这个问题呢?
我们对原序列a中的元素依次访问 , 记为a[i] , 并对应至d中相应的元素d[k](?) , 更新dp[k]=sum( dp[j] , 1<= j <k ) + 1。
为什么不用考虑顺序的问题了?因为此时只有原序在d[k]之前的元素被更新过。
而求和操作可以利用树状数组来实现。
(?)这里可以发现,a[i]到d[k]的对应是有问题的,这里用到了离散化( 排序,去重,二分对应标号 )。(ps:其实离散化这个概念我刚接触,也还不太懂。。。希望懂的人不吝赐教)
//另外,当a[i]范围比较小时,可以不用离散化,直接以a[i]的值作为对应标号即可。
这样,这个问题在O(nlogn)的复杂度下Accepted了。
View Code
1 //hdu2227 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N = 100005,MOD = 1000000007; 7 typedef unsigned int LL; 8 LL a[N],d[N],hash[N]; 9 int n,tot,c[N]; 10 11 int lowbit(int x) {return x&(-x);} 12 13 void add(int id,int x) 14 { 15 for(int i=id;i<=tot;i+=lowbit(i)) 16 c[i] = (c[i]+x)%MOD; 17 } 18 19 int query(int id) 20 { 21 int sum=0; 22 for(int i=id;i>=1;i-=lowbit(i)) 23 sum=(sum+c[i])%MOD; 24 return sum; 25 } 26 27 int binsearch(LL x) 28 { 29 int i=1,j=tot,mid; 30 31 while( i<=j ) 32 { 33 mid=(i+j)/2; 34 if( hash[mid]==x ) return mid; 35 if( hash[mid]<x ) i=mid+1; 36 else j=mid-1; 37 } 38 } 39 40 int main() 41 { 42 while( ~scanf("%d",&n) ) 43 { 44 for(int i=1;i<=n;i++) 45 { 46 scanf("%u",&a[i]); 47 d[i]=a[i]; 48 } 49 sort(d+1,d+n+1); 50 tot=1; 51 hash[1]=d[1]; 52 for(int i=2;i<=n;i++) 53 if( d[i]!=d[i-1] ) 54 hash[++tot]=d[i]; 55 memset(c+1,0,tot*sizeof(c[0])); 56 for(int i=1;i<=n;i++) 57 { 58 int id=binsearch(a[i]); 59 int tmp=query(id); 60 add(id,tmp+1); 61 } 62 printf("%d\n",query(tot)); 63 } 64 return 0; 65 }
hdu3450和hdu2227类似,就不解释了。
View Code
1 //hdu3450 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N = 100005,MOD = 9901; 7 8 int a[N],b[N],hash[N],c[N],tot; 9 10 int lowbit(int x) {return x&(-x);} 11 12 void add(int id,int x) 13 { 14 for(int i=id;i<=tot;i+=lowbit(i)) 15 c[i]= (c[i]+x)%MOD; 16 } 17 18 int query(int id) 19 { 20 int sum=0; 21 for(int i=id;i>=1;i-=lowbit(i)) 22 sum = (sum+c[i])%MOD; 23 return sum; 24 } 25 26 int findR(int v) 27 { 28 int i=1,j=tot+1,mid; 29 30 while( i<j ) 31 { 32 mid=(i+j)/2; 33 if( hash[mid]<=v ) i=mid+1; 34 else j=mid; 35 } 36 return i-1; 37 } 38 39 int findL(int v) 40 { 41 int i=1,j=tot+1,mid; 42 43 while( i<j ) 44 { 45 mid=(i+j)/2; 46 if( hash[mid]<v ) i=mid+1; 47 else j=mid; 48 } 49 return i-1; 50 } 51 52 int main() 53 { 54 int n,d; 55 56 while( ~scanf("%d%d",&n,&d) ) 57 { 58 for(int i=1;i<=n;i++) 59 { 60 scanf("%d",&a[i]); 61 b[i]=a[i]; 62 } 63 sort(b+1,b+n+1); 64 tot=1; 65 hash[1]=b[1]; 66 for(int i=2;i<=n;i++) 67 if( b[i]!=b[i-1] ) 68 hash[++tot]=b[i]; 69 memset(c+1,0,tot*sizeof(c[0])); 70 for(int i=1;i<=n;i++) 71 { 72 int L=findL(a[i]-d),id=findL(a[i])+1,R=findR(a[i]+d); 73 int tmp=query(R)-query(L); 74 add(id,tmp+1); 75 } 76 printf("%d\n",((query(tot)-n)%MOD+MOD)%MOD); 77 } 78 return 0; 79 }