[Manthan, Codefest 18][Codeforces 1037F. Maximum Reduction]
题目链接:1037F - Maximum Reduction
题目大意:给出一段代码,给你一个长度为n的数组和数字k,求程序运行结果,mod 1e9+7输出
简单翻译下代码的意思,初始定义一个空数组b,分别查询区间[1,k];[2,k+1];...;[n-k+1,n]的最大值,并将这 n-k+1 个区间最大值放入b,将b中元素之和加入到ans里,并把这个长度为n-k+1的数组b放入到下一层的递归,这样就要再求n-2k+1次、n-3k+1次最大值,直到数组的长度小于k(即无法求区间长度为k的最大值)
题解:我一开始也不知道从何入手,于是就写了下当n=10,k=3的时候要求的是哪些区间最大值的和,写出来是这样
[1,3][2,4][3,5][4,6][5,7][6,8][7,9][8,10]
[1,5][2,6][3,7][4,8][5,9][6,10]
[1,7][2,8][3,9][4,10]
[1,9][2,10]
可以发现当左端点 l 固定的时候,右端点只可能是 l+t(k-1),称这样的区间是有用的区间
然后我们再来考虑另外一件事情,对于上述的每一个区间,这些区间的最大值都是这些区间中的某一个数【废话←_←】
于是我们就可以开始考虑每个数被当做区间最大值的次数是多少这个问题。对于任意一个位置x上的数,他都是有一个影响范围的,即在这个范围里,任意一个包含x的区间,a[x]都是这个区间内的最大值。因此我们要先预处理出每个数的左边最后一个比他小的数是多少,他右边最后一个比他小的数是多少,记为l[i],r[i],显然区间[ l[i],r[i] ]是a[i]这个数的影响范围。这时对任意的x,我们只需要求出在区间[ l[x],r[x] ]内,有多少个有用的区间包含x
那怎么计算有用区间的个数呢?这就需要用到之前求出的性质了。显然一个区间[l,r]有用,当且仅当 (r-l)=t(k-1) 其中t为正整数。因此区间[l,r]中以l为左端点的有用的区间个数为 \(\left \lfloor \frac{r-l}{k-1} \right \rfloor\) ,故区间[l,r]中的有用区间数为 \(\sum_{i=l}^{r}\left \lfloor \frac{r-i}{k-1} \right \rfloor\) 。但注意到,这些区间里有一些是没有包含到x的,所以若设g(l,r,x)表示区间[l,r]中包含x的有用区间数,则$$g(l,r,x)=\sum_{i=l}^{x}\left \lfloor \frac{r-i}{k-1} \right \rfloor - \sum_{i=l}^{x-1}\left \lfloor \frac{x-1-i}{k-1} \right \rfloor$$
这个式子表示的就是左端点在x及x左边的有用区间总数 减去 右端点小于x的有用区间总数。这样循环一遍的复杂度是O(2(x-l)),也就是说如果直接暴力求解的话是铁定会超时的,所以我们需要进一步优化
upd:看到这里可以直接点开评论区第一条回复,用预处理前缀和优化即可
这里优化的姿势有两种,一种是考虑这个式子可以转换为若干个等差数列之和,直接套公式就好,这种做法写起来简单但需要一定时间思考,当时做这道题的时候懒得细想就用了另一种方法
第二种方法就是用类欧几里得算法做了,由于本人比较菜,对这方面的知识不太了解,也只会套模板,就不详细介绍了_(:з」∠)_这个相关的知识点百度一下都有的233333
类欧几里得算法可以对 \(f(a,b,c,n)=\sum_{i=0}^{n}\left \lfloor \frac{ai+b}{c} \right \rfloor\)这样的函数进行复杂度为O(log n)的计算,可以发现\(g(l,r,x)=f(1,r-x,k-1,x-l)-f(1,0,k-1,x-l-1)\)。于是将之前求得的式子对着板子套进去就可以快速求解了~
#include<bits/stdc++.h>
using namespace std;
#define N 1000001
#define LL long long
#define MOD 1000000007
LL n,k,a[N],l[N],r[N],ans;
LL S(LL k){return (k*(k+)/2ll)%MOD;}
LL f(LL a,LL b,LL c,LL n)
{
if(!a)return ;
if(a>=c || b>=c)
return ((a/c)*S(n)%MOD+(n+)*(b/c)%MOD+f(a%c,b%c,c,n))%MOD;
LL m=(a*n+b)/c;
return (m*n%MOD-f(c,c-b-,a,m-)+MOD)%MOD;
}
LL get(LL l,LL r,LL x)
{
return (f(,r-x,k,x-l)-f(,,k,x-l-)+MOD)%MOD;
}
int main()
{
scanf("%I64d%I64d",&n,&k);
for(LL i=;i<=n;i++)
scanf("%I64d",&a[i]);
l[]=,r[n]=n;
for(LL i=;i<=n;i++)
{
LL _=i;
while(_> && a[i]>=a[_-])
_=l[_-];
l[i]=_;
}
for(LL i=n-;i>=;i--)
{
LL _=i;
while(_<n && a[i]>a[_+])
_=r[_+];
r[i]=_;
}
k--;
for(LL i=;i<=n;i++)
ans+=get(l[i],r[i],i)*a[i]%MOD,ans%=MOD;
printf("%I64d\n",ans);
return ;
}
可以发现由于这里的套模板的a为1,所以最多递归两次就能得到答案,因此这部分的时间复杂度可以看成O(n)
另外还有一个注意事项,就是在处理数组l,r的时候要半开半闭地处理,即往右边是找小于等于,往左边是找小于这样,否则当出现重复的数字的时候会重复计算答案
[Manthan, Codefest 18][Codeforces 1037F. Maximum Reduction]的更多相关文章
- [Manthan, Codefest 18][Codeforces 1037E. Trips]
题目链接:1037E - Trips 题目大意:有n个人,m天,每天晚上都会有一次聚会,一个人会参加一场聚会当且仅当聚会里有至少k个人是他的朋友.每天早上都会有一对人成为好朋友,问每天晚上最多能有多少 ...
- Codeforces 1037F. Maximum Reduction
总感觉我这种做法会T,一直没写,看了其他人的题解也是这样,,,就果断写了,,可能数据不太深,或者玄学复杂度 题意即求xk-1长度的所有区间的最大值的和,对每一个i(数组下边),他对答案的贡献数量就是在 ...
- Codeforces Manthan, Codefest 18 (rated, Div. 1 + Div. 2) D,E
D. Valid BFS? time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- Codeforces Manthan, Codefest 18 (rated, Div. 1 + Div. 2) E.Trips
比赛的时候想到怎么做了 没调出来(感觉自己是个睿智) 给你N个点M条边,这M条边是一条一条加进去的 要求你求出加入每一条边时图中极大'K度'子图的大小 极大'K度'子图的意思是 要求出一个有尽量多的点 ...
- Manthan, Codefest 18 (Div 1 + Div 2) (A~E)
目录 Codeforces 1037 A.Packets B.Reach Median C.Equalize D.Valid BFS E.Trips(正难则反) Codeforces 1037 比赛链 ...
- Manthan, Codefest 18 (rated, Div. 1 + Div. 2) F 单调栈 + 贡献 + 计数
https://codeforces.com/contest/1037/problem/F 题意 function z(array a, integer k): if length(a) < k ...
- Manthan, Codefest 18 (rated, Div. 1 + Div. 2) E bfs + 离线处理
https://codeforces.com/contest/1037/problem/E 题意 有n个人,m天,在第i天早上,x和y会成为朋友,每天晚上大家都要上车,假如一个人要上车那么他得有至少k ...
- Manthan, Codefest 18 (rated, Div. 1 + Div. 2) C D
C - Equalize #include<bits/stdc++.h> using namespace std; using namespace std; string a,b; int ...
- 题解——CF Manthan, Codefest 18 (rated, Div. 1 + Div. 2) T5(思维)
还是dfs? 好像自己写的有锅 过不去 看了题解修改了才过qwq #include <cstdio> #include <algorithm> #include <cst ...
随机推荐
- 无法打开运行空间池,服务器管理器winrm插件可能已损坏或丢失
在使用windows2012 的服务器或云主机时,服务器安装不了iis服务. 提示 “无法打开运行空间池,服务器管理器winrm插件可能已损坏或丢失”. 这个问题可能的原因是您的机器未设置虚拟内存,可 ...
- iOS10 11跳转系统设置等的URL收集
Settings App-Prefs:root Settings -> About App-Prefs:root=General&path=About Settings -> Ac ...
- 关闭windows10更新
除了能够禁用Windows自动更新外,还能一键禁用Windows安全中心.Windows Defender.Windows防火墙. 下载地址 https://files.cnblogs.com/fil ...
- ABAP非Unicode系统中字符串拼接(CONCATENATE)时吃字符问题
系统是老R3,非Unicdoe系统,某些表字段是从外界系统过来的,由于接口设计的固定长度,外界系统传超长字符串过来后,就可能从最后一个中文字符中间截断,这问题到还没什么,只不过显示时最后一个字符显示成 ...
- C# Task WhenAny和WhenAll 以及TaskFactory 的ContinueWhenAny和ContinueWhenAll的实现
个人感觉Task 的WaitAny和WhenAny以及TaskFactory 的ContinueWhenAny有相似的地方,而WaitAll和WhenAll以及TaskFactory 的Continu ...
- Docker 的插件式设计
http://www.tuicool.com/articles/MnIRZvJ http://uzhima.com/2016/08/02/what-is-docker-volume-plugin/ 在 ...
- IsDebuggerPresent原理及其 c++实现
在IsDebuggerPresent下断,步入得到如下代码: 75 A1 | ] | eax:std::cout 75 | ] | eax:std::cout 75 | ] | eax:std::co ...
- MySQL技术内幕读书笔记(一)——Mysql体系结构和存储引擎
目录 MySQL体系结构和存储引擎 定义数据库和实例 MYSQL体系结构 MYSQL存储引擎 MySQL体系结构和存储引擎 定义数据库和实例 数据库:物理操作系统文件或者其他形式文件类型的结合.在MY ...
- SQL SERVER数据库删除LOG文件和清空日志的方案
原文:SQL SERVER数据库删除LOG文件和清空日志的方案 数据库在使用过程中会使日志文件不断增加,使得数据库的性能下降,并且占用大量的磁盘空间.SQL Server数据库都有log文件,log文 ...
- Sublime插件Emmet的安装及Tab补全代码
Emmet是一款Web前端开发工具Sublime非常有用的插件,使用仿CSS选择器的语法来生成代码,大大提高了HTML和CSS代码编写的速度,只需按住Tab键即可把一个简写展开成HTML和CSS的代码 ...