LG-P2804 神秘数字/LG-P1196 火柴排队 归并排序, 逆序对

P2804-神秘数字

题目描述(简化版)

有 n 个数,求这 n 个数中,有多少个连续的数的平均数大于某个给定的数 M?

注意:这个数可能会很大,请输出这个数对92084931取模的结果。

输入输出格式

输入格式:

共两行。

第一行为两个数 n 和 M。

第二行为 n 个数。

输出格式:

一行一个数,即问题的解对92084931取模的结果

输入输出样例

输入样例#1:
4 3
1 5 4 2
输出样例#1:
5
输入样例#2:
4 4
5 2 7 3
输出样例#2:
6

说明

【样例解释】

①对于这4个数,问题的解有{5},{4},{5,4},{1,5,4},{5,4,2}共5组。

②对于这4个数,问题的解有{5},{7},{2,7},{7,3},{5,2,7},{5,2,7,3}共6组。

【数据规模】

对于10%的数据,1<n≤10.

对于30%的数据,1<n≤1000.

对于50%的数据,1<n≤30000.

对于100%的数据,1<n≤200000,1<M≤3000,每个数均为正整数且不大于5000.

 

分析

把数列中的 n 个数字都减去 m。那么某一段的和大于0就是满足要求的一段。

于是问题就转化为:求当前数列中有多少个区间的和大于0。

很容易求出数列的前缀和,放在数组 p 中。

如果第 i 个数到第 j 个数满足要求(假定 i<j),很容易想到 p[j]-p[i-1]>0。

也就是说:p[j]>p[i-1]

问题转化为:求 p[j] 之前有多少个 p[i]>p[j],把相对于每一个p[j]的答案个数相加就是 ans

也就是求前缀和数列p的逆序对

期望复杂度O(nlogn)

程序:

100%

 1 // 100% answer
 2 // Merge Sort
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 using namespace std;
 7 const int MAX = 200000 + 1;
 8 int n, avg, p[MAX], a[MAX], tmp[MAX], ans;
 9 int merge(int l,int mid,int r)
10 {
11     int i=l, j=mid+1, k=l-1;
12     while(i<=mid && j<=r)
13     {
14         if(p[i]<p[j])
15         {
16             ans+=(mid-i+1);
17             ans%=92084931;
18             tmp[++k]=p[j];
19             j++;
20         }
21         else
22         if(p[i]>=p[j])
23         {
24             tmp[++k]=p[i];
25             i++;
26         }
27     }
28     while(i<=mid)
29         tmp[++k]=p[i++];
30     while(j<=r)
31         tmp[++k]=p[j++];
32     for(int i=l;i<=r;i++)
33         p[i]=tmp[i];
34 }  
35 void MergeSort(int l, int r)
36 {
37     if (l < r)
38     {
39         int mid = (l+r) >> 1;
40         // int mid = (l+r)/2;
41         MergeSort(l,mid);
42         MergeSort(mid+1,r);
43         merge(l,mid,r);
44     }
45 }
46 int main()
47 {
48     cin >> n >> avg;
49     p[0] = 0;
50     for (int i = 1; i <= n; i++)
51     {
52         cin >> a[i];
53         a[i] -= avg;
54         p[i] = p[i-1] + a[i];
55     }
56     MergeSort(0,n);
57     cout << ans << endl;
58     return 0;
59 }
View Code

 45%

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int MOD = 92084931;
 6 int main()
 7 {
 8     int n,avg,a[200000],p[200000];
 9     cin >> n >> avg;
10     p[0] = 0;
11     for (int i = 1; i <= n; i++)
12     {
13         cin >> a[i];
14         p[i] = p[i-1] + a[i];
15     }
16     int ans = 0;
17     for (int i = 1; i <= n; i++)
18         for (int j = i; j <= n; j++)
19         {
20             if ((p[j]-p[i-1])>(avg*(j-i+1)))
21             {
22                 ans++;
23             }
24         }
25     cout << ans%MOD << endl;
26     return 0;
27 }
View Code

 

转载于:https://www.cnblogs.com/OIerPrime/p/7966649.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值