[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 ...
随机推荐
- Python常用的软件包
下面是Python开发常用的软件包. 名称 用途 安装命令 opengl sudo pip3 install PyOpenGL pyqtgraph GUI图形库 sudo pip3 instal ...
- 为Ubuntu新创建用户创建默认.bashrc并自动加载
首先,su – 到新创建的用户 拷贝默认的.bashrc过来 1 cp /etc/skel/.bashrc ~/ 然后创建.profile文件 1 vi ~/.profile 粘贴下面的内容 ...
- HTML动画 request animation frame
在网页中,实现动画无外乎两种方式.1. CSS3 方式,也就是利用浏览器对CSS3 的原生支持实现动画:2. 脚本方式,通过间隔一段时间用JavaScript 来修改页面元素样式来实现动画.接下来我们 ...
- VUE温习:nextTick、$refs、嵌套路由、keep-alive缓存、is特性、路由属性用法、路由钩子函数
一.$nextTick 1.vue的dom执行异步更新,只要观察到数据变化,vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变. 2.vue.$nextTick(cb),数据发生变化,更新 ...
- AWStats日志分析系统
1.什么是AWStats AWStats是一款功能强大且功能强大的免费工具,可以图形方式生成高级Web,流媒体,ftp或邮件服务器统计信息.此日志分析器用作CGI或命令行, 并在几个图形网页中显示您的 ...
- 在三台Centos或Windows中部署三台Zookeeper集群配置
一.安装包 1.下载最新版(3.4.13):https://archive.apache.org/dist/zookeeper/ 下载https://archive.apache.org/dist/ ...
- P2P贷款全攻略,贷前、贷中、贷后工作事项解析
一.贷前调查事项 贷前调查是所有银行.小贷.P2P等等往出贷款部门的重中之重. 归根结底就是两条:让不对称信息最大限度对称.让软信息最大限度真实还原. 客户还不还款就是取决两大因素:还款能力.还款意愿 ...
- xcode10 改动
xcode10 开发环境 比 之前有了稍微的变动 1. 代码块 界面控件 图片资源等 的查看位置发生了变化 之前的开发环境 代码块 统一放在 右侧栏的下方的几个选项中 现在 统一放到了上方 ...
- server后台TCP连接存活问题
公司的server后台部署在某一个地方,接入的是用户的APP,而该地方的网络信号较差,导致了server后台在执行一段时间后用户无法接入,那边的同事反馈使用netstat查看系统.存在较多的TCP连接 ...
- Unity应用架构设计(3)——构建View和ViewModel的生命周期
对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者在各个阶段 ...