序列
序列
1s/64MB
[Description]
有一天 OJ 给 Jiangzh 了一个序列,但是 OJ 给的任务没有省选 operation 那么变态,OJ 只需要 Jiangzh 做两件事:
① 求出这个序列的最长上升子序列长度 ② 这个序列中满足 i < j < k Ai < Aj > Ak 关系的序列个数
[Input]
第一行一个整数 N,表示这个序列有 N 个整数第二行 N 个整数 Ai
[Output]
两行,每行一个整数分别为两个问题的答案
[Sample 1]
sequence.in |
sequence.out |
|
|
5 |
5 |
1 2 3 4 5 |
0 |
|
|
样例解释:最长上升子序列长度为 5,满足条件②的序列有 0个
[Sample 2]
sequence.in |
sequence.out |
|
|
5 |
4 |
1 5 3 4 8 |
2 |
|
|
样例解释:最长上升子序列长度为 4,满足条件②的序列有 2个 ——(1,5,3)和 (1,5,4)
[Hit]
对于 30%的数据:N<=200
对于 50%的数据:N<=5000
对于 100%的数据:N<=100000,0<=Ai<=200000
题解:
实际上是两道经典题并在了一起。
由于数据范围,这道题两问都得用O(nlogn)算法,第一问维护一个树状数组保存比i小的数的个数,用一个数组p来确定每次更新的范围,每次更新的时候一定要注意不要更新多了。第二问则需要维护两个树状数组,一个从后往前,一个从前往后,然后统计一下两个的乘积就可以了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 typedef long long lol; 9 lol n,a[200005],s[100005],f[100005],mmax,p[100005],ans; 10 lol gi() 11 { 12 lol ans=0,f=1; 13 char i=getchar(); 14 while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} 15 while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} 16 return ans*f; 17 } 18 lol lowbit(lol x){return x&(-x);} 19 void add(lol x,lol v) 20 { 21 for(lol i=x;i<=mmax;i+=lowbit(i)) 22 a[i]+=v; 23 } 24 lol getsum(lol x) 25 { 26 lol ans=0; 27 for(lol i=x;i;i-=lowbit(i)) 28 ans+=a[i]; 29 return ans; 30 } 31 lol b[200005],c[100005]; 32 void addb(lol x,lol v) 33 { 34 for(lol i=x;i<=mmax;i+=lowbit(i)) 35 b[i]+=v; 36 } 37 lol getsumb(lol x) 38 { 39 lol ans=0; 40 for(lol i=x;i;i-=lowbit(i)) 41 ans+=b[i]; 42 return ans; 43 } 44 int main() 45 { 46 freopen("sequence.in","r",stdin); 47 freopen("sequence.out","w",stdout); 48 lol i,j; 49 n=gi(); 50 for(i=1;i<=n;i++) 51 s[i]=gi()+2,mmax=max(mmax,s[i]); 52 for(i=1;i<=n;i++)p[i]=mmax; 53 add(s[1],1); 54 p[1]=s[1]; 55 f[1]=1; 56 ans=1; 57 for(i=2;i<=n;i++) 58 { 59 f[i]=getsum(s[i])+1; 60 if(p[f[i]-1]==s[i]){f[i]--;ans=max(ans,f[i]);continue;} 61 add(s[i],1); 62 if(p[f[i]]!=mmax) 63 add(p[f[i]],-1); 64 p[f[i]]=s[i]; 65 ans=max(ans,f[i]); 66 } 67 printf("%I64d\n",ans); 68 ans=0; 69 for(i=1;i<=n;i++) 70 { 71 c[i]=getsumb(s[i]); 72 addb(s[i]+1,1); 73 } 74 memset(b,0,sizeof(b)); 75 for(i=n;i>=1;i--) 76 { 77 ans+=c[i]*getsumb(s[i]); 78 addb(s[i]+1,1); 79 } 80 printf("%I64d\n",ans); 81 return 0; 82 }