bzoj5157: [Tjoi2014]上升子序列(树状数组LIS)
5157: [Tjoi2014]上升子序列
题目:传送门
题解:
学一下nlogn的树状数组求最长上生子序列就ok(%爆大佬)
离散化之后,用一个数组记录一下,直接树状数组做
吐槽:妈耶...一开始不会lower_bound 的蒟蒻用手打二分离散化...结果去重了...然后屁颠屁颠的学了lower_bound(很好用!)
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #define mod 1000000007 7 using namespace std; 8 int n,a[110000],wa[110000],s[110000]; 9 int lowbit(int x){return x&-x;} 10 void add(int x,int p) 11 { 12 while(x<=n) 13 { 14 s[x]=(s[x]+p)%mod; 15 x+=lowbit(x); 16 } 17 } 18 int getsum(int x) 19 { 20 int ans=0; 21 while(x) 22 { 23 ans=(ans+s[x])%mod; 24 x-=lowbit(x); 25 } 26 return ans; 27 }/* 28 int LS(int x) 29 { 30 int l,r,mid,ans; 31 l=1,r=n; 32 while(l<=r) 33 { 34 mid=(l+r)/2; 35 if(wa[mid]<=x) 36 { 37 l=mid+1; 38 ans=mid; 39 } 40 else r=mid-1; 41 } 42 return ans; 43 }*/ 44 int f[110000],last[110000],w[110000]; 45 int main() 46 { 47 scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),wa[i]=a[i]; 48 sort(wa+1,wa+n+1);int sum=0;memset(f,0,sizeof(f)); 49 for(int i=1;i<=n;i++) 50 { 51 a[i]=lower_bound(wa+1,wa+n+1,a[i])-wa;if(w[a[i]]==0)sum++; 52 last[i]=w[a[i]];w[a[i]]=i;//链表记录上次影响的位置 53 } 54 for(int i=1;i<=n;i++) 55 { 56 f[i]=getsum(a[i]-1)+1;//这个数能贡献的上升子序列个数 57 add(a[i],(f[i]-f[last[i]]+mod)%mod);//减去重复的贡献 58 } 59 int ans=getsum(n); 60 printf("%d\n",(ans-sum+mod)%mod); 61 return 0; 62 }