2307. 选择

题目描述

 

输入

输出

 

样例输入

样例输出

 

数据范围限制

 

提示

【样例解释】
样例一:L = 1, R = 3 样例二:L = 2, R = 5 

题解:

这一题,是一道经典的前缀和问题。但是这里单单用前缀和就会N2超时。

所以呢,我们要换一种思路。

我们设fife的随从为A组,beny的随从为B组。sumxt表示T组的下标为X的战斗力(能力值的前缀和)。

所以原式就转换成求一下这个鬼东西的最小值:(设区间左边为L,右边为R)

abs(sumRA-sumLA-(sumRB-sumLB))(1<=L<=R<=n)

而上面那个鬼东西又等于下面这个鬼东西:

abs((sumRA-sumRB)-(sumLA-sumLB))(1<=L<=R<=n)———①

所以你就可以把sumRA-sumRB与sumLA-sumLB看成一种新的前缀和s,所以我们设:

si=sumiA-sumiB(1<=i<=n)

这样我们就把①式转化成了下面这个简洁的式子:

abs(sR-sL)

其实上面那个式子就是求两个s值的最小的差值。

对于这个,我们只要将s数组快排一遍,然后再枚举i,找出最小的si-si-1就够了。

为什么呢?因为当你排完了序之后,相邻的数总会在数轴上总会最靠近那个数(在同侧)。

所以相邻的数一定比不相邻的数(在同侧)的数更优。

所以我们就这样得出了答案。

 

看一看时间复杂度:

输入:O(N)

前缀和:O(N)

求s数组:O(N)

快排:O(N*log(N))

求最小值:O(N)

 

综上可得:我们的时间复杂度是O(N*log(N))。

 

万事俱备,只欠代码!

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long n,x,y,min1=0x3f3f3f3f,s1[300001],s2[300001],s[300001];
 4 //由于数据大小300000*1000000000肯定会爆int,所以要开long long! 
 5 int main()
 6 { 
 7     scanf("%lld",&n);
 8     for(int i=1;i<=n;i++)
 9     {
10         scanf("%lld",&x);
11         s1[i]=s1[i-1]+x;    
12     }
13     for(int i=1;i<=n;i++)
14     {
15         scanf("%lld",y);
16         s2[i]=s2[i-1]+y;
17         s[i]=s1[i]-s2[i];
18     }
19     sort(s+1,s+n+1);
20     for(int i=1;i<=n;i++)
21     min1=min(min1,abs(s[i]-s[i-1]));
22     printf("%lld",min1);
23     return 0;
24 }

此题到此完结!

posted @ 2019-08-12 19:17  人之常路  阅读(134)  评论(0编辑  收藏  举报