序列

序列

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 }

 

转载于:https://www.cnblogs.com/huangdalaofighting/p/7221244.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值