题目链接: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]的更多相关文章

  1. [Manthan, Codefest 18][Codeforces 1037E. Trips]

    题目链接:1037E - Trips 题目大意:有n个人,m天,每天晚上都会有一次聚会,一个人会参加一场聚会当且仅当聚会里有至少k个人是他的朋友.每天早上都会有一对人成为好朋友,问每天晚上最多能有多少 ...

  2. Codeforces 1037F. Maximum Reduction

    总感觉我这种做法会T,一直没写,看了其他人的题解也是这样,,,就果断写了,,可能数据不太深,或者玄学复杂度 题意即求xk-1长度的所有区间的最大值的和,对每一个i(数组下边),他对答案的贡献数量就是在 ...

  3. 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 ...

  4. Codeforces Manthan, Codefest 18 (rated, Div. 1 + Div. 2) E.Trips

    比赛的时候想到怎么做了 没调出来(感觉自己是个睿智) 给你N个点M条边,这M条边是一条一条加进去的 要求你求出加入每一条边时图中极大'K度'子图的大小 极大'K度'子图的意思是 要求出一个有尽量多的点 ...

  5. 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 比赛链 ...

  6. 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 ...

  7. Manthan, Codefest 18 (rated, Div. 1 + Div. 2) E bfs + 离线处理

    https://codeforces.com/contest/1037/problem/E 题意 有n个人,m天,在第i天早上,x和y会成为朋友,每天晚上大家都要上车,假如一个人要上车那么他得有至少k ...

  8. 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 ...

  9. 题解——CF Manthan, Codefest 18 (rated, Div. 1 + Div. 2) T5(思维)

    还是dfs? 好像自己写的有锅 过不去 看了题解修改了才过qwq #include <cstdio> #include <algorithm> #include <cst ...

随机推荐

  1. centos安装系统全过程

    --查看系统 lsb_release -a --查看端口 netstat -lnp|grep 80 ps 进程ID #查看进程的详细信息 kill -9 进程ID --查看Java 版本 java - ...

  2. fastjson转换json字符串key的首字母小写变大写的解决办法

    https://blog.csdn.net/erbao_2014/article/details/53688934 问题描述在开发过程中,由于接口文档的描述,要求json字符串的key首字母为大写,而 ...

  3. 【转】fiddler抓包HTTPS请求

    本文转自:http://blog.csdn.net/idlear/article/details/50999490 fiddler抓包HTTPS请求 跟着教程来,保证100%成功抓HTTPS包 教程开 ...

  4. VuePress

    VuePress 这篇文章主要是记录自己在使用VuePress过程中所遇到的问题以及如何一步一步的解决问题. 安装vuepress前,请确保你的 Node.js 版本 >= 8 全局安装 # 安 ...

  5. 记一次免费让网站启用HTTPS的过程

    写在前面 个人网站运行将近2个月了,期间根据酷壳的一篇教程如何免费的让网站启用HTTPS做了一次,中间遇到问题就放下了.昨天孙三苗问我网站地址说要添加友链,出于好奇想看他网站长什么样,顺道也加一下友链 ...

  6. Redis】Java中使用Jedis操作Redis(Maven导入包)、创建Redis连接池

    如果我们使用Java操作Redis, 需要确保已经安装了 redis 服务及 Java redis 驱动. Maven项目可以直接在pom.xml中加入jedis包驱动: <!-- https: ...

  7. Down Payment 和 Deposit的差异

    If you’re like most homeowners, purchasing a home represents the single biggest financial transactio ...

  8. CentOS 7.X 安全手记

    一.安装云锁 1.报错 Install Selinux Policy Module:yunsuo_install/install: line 371: checkmodule: command not ...

  9. 音视频编解码: YUV存储格式中的YUV420P,YUV420SP,NV12, NV21理解(转)

    概述  之前介绍了YUV码流的采样格式,下面分析下YUV码流的存储格式,YUV码流的存储格式与采样格式息息相关.总的来讲,YUV存储格式主要分为两种: planar 平面格式 指先连续存储所有像素点的 ...

  10. Python3 File

    open() 方法 Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError. 注意:使用 open() ...