acdream 小晴天老师系列——我有一个数列! (ST算法)

  小晴天老师系列——我有一个数列!

Time Limit:  20000/10000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Others)
Submit  Status

Problem Description

小晴天:“我有一个数列!”

小晴天:“我还要有很多很多的数列!”

于是小晴天就把这个数列的所有连续子数列写出来。

然后小晴天把每个连续子数列中的最大的数写出来。

那么,有多少个比K大呢?

Input

多组数据,首先是一个正整数t(t<=100),表示数据的组数

对于每组数据,首先是两个整数n(1<=n<=200000),K(0<=K<=10^9).,但所有数据中的n之和不超过1000000.

接下来是n个整数a[i](1<=a[i]<=10^9)

 

Output

对于每组数据,输出一个整数,表示最大元素大于K的连续子序列的个数。

Sample Input

2

3 2

1 2 3 

3 1 

1 2 3

Sample Output

3

5

Hint

对于样例一,共有6个连续子序列{1}{2}{3}{1,2}{2,3}{1,2,3}(注意{1,3}不满足题意,因为不连续)

其中最大元素大于2的共有3个{3}{2,3}{1,2,3}

对于样例二,大于1的连续子序列共有5个,{2}{3}{1,2}{2,3}{1,2,3}

 

 

 

 

思路:ST算法可以解决。用 O(n*n)穷举每个区间,用ST算法在O(1)找到每个区间的最大再与k比较。

 

 

 1 /*

 2 * this code is made by xcw0754

 3 * Problem: 1706

 4 * Verdict: Accepted

 5 * Submission Date: 2015-07-15 15:30:18

 6 * Time: 512MS

 7 * Memory: 29024KB

 8 */

 9 #include <bits/stdc++.h>

10 #define LL long long

11 #define pii pair<int,int>

12 #define INF 0x7f7f7f7f

13 using namespace std;

14 const int N=200000+50;

15  

16 int w[N], pre[N][32], n, q, k, t;

17 int tmp[N];

18 int cnt[N];

19 void init()//先处理,减少复杂度

20 {

21     for(int j=1; j<N; j++)

22     {

23         int c=0;

24         for(int i=0; i<30; i++)//找出二进制最高位的1

25         {

26             if(!(j>>i))

27             {

28                 tmp[j]=((j>>(i-1))<<(i-1));

29                 break;

30             }

31             c++;

32         }

33         cnt[j]=c;

34     }

35 }

36  

37 void pre_cal()//ST预处理

38 {

39     for(int i=0; i<n; i++)    pre[i][0]=w[i];

40     for(int i=2,q=1; i<=n; i*=2,q++)

41         for(int j=0; j<n; j++)

42             if(j+i-1<n)    pre[j][q]=max(pre[j][q-1],pre[j+i/2][q-1]);

43             else    break;

44 }

45  

46  

47  

48 int cal()

49 {

50     int ans=0;

51     for(int i=0; i<n; i++)

52     {

53         if(w[i]>k)  ans++;

54  

55         for(int j=i+1; j<n; j++)

56         {

57             int len=j-i+1, tmp=0, cnt=0;

58             for(int i=0; i<30; i++)//找出二进制最高位的1

59             {

60                 if(!(len>>i))

61                 {

62                     tmp=((len>>(i-1))<<(i-1));

63                     break;

64                 }

65                 cnt++;

66             }

67  

68             int big= max(pre[ i ][cnt-1],pre[ j-tmp+1 ][cnt-1]);

69             if(big>k)  ans++;

70         }

71     }

72     return  ans;

73 }

74  

75 int main()

76 {

77     //freopen("input.txt", "r", stdin);

78     cin>>t;

79     while(t--)

80     {

81         scanf("%d%d",&n, &k);

82         for(int i=0; i<n; i++)    scanf("%d",&w[i]);

83         pre_cal();

84         printf("%d\n",cal());

85     }

86     return 0;

87 }
AC代码

 

 

 

你可能感兴趣的:(算法)