[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 ...
随机推荐
- Deepin 15.4 升级 chrome flash
到 adobe 官方下载 flash插件 flash_player_ppapi_linux ~/.config/google-chrome/PepperFlash下建个目录 23.0.0.185,把 ...
- ASP.NET Core 发布
ASP.NET Core 发布,asp.netcore发布 第一步:运行 dotnet restore 命令,以还原项目中指定的依赖项 dotnet restore 第二步:使用 dotnet bui ...
- Java的内存管理机制之内存区域划分
各位,好久不见.先做个预告,由于最近主要在做Java服务端开发,最近一段时间会更新Java服务端开发相关的一些知识,包括但不限于一些读书笔记.框架的学习笔记.和最近一段时间的思考和沉淀.先从Java虚 ...
- Linux出现Read-only file system错误的解决方法
造成这个问题的解决办法大多数是由于非正常关机后导致文件系统受损引起的,在系统重新启动之后,受损分区就会被Linux自己主动挂载为仅仅读.解决办法是通过fsck来修复文件系统,然后重新启动就可以,下面是 ...
- SQLAlchemy——获取某列为空的数据
session.query(StockAllInfo).filter( StockAllInfo.ts_code == tsCode and StockAllInfo.py_code==None).a ...
- Convert ResultSet to JSON and XML
public static JSONArray convertToJSON(ResultSet resultSet) throws Exception { JSONArray jsonArray = ...
- 为RecyclerView打造通用Adapter
##RecycleView简单介绍 RecyclerView控件和ListView的原理有非常多相似的地方,都是维护少量的View来进行显示大量的数据.只是RecyclerView控件比ListVie ...
- 福利:42套AI技术视频免费领取
<福利:33套AI技术视频免费领取> 视频获取方式:请加机器学习和自然语言(QQ群号:436303759)群后,私信群主获取(备注上自己想要获取是视频名称),仅限本群公众号粉丝成员,多套视 ...
- mybatis检测mysql表是否存在
1.优先使用information_schema来检查,如果没有查询这个的权限则使用show tables来检查. mapper: import java.util.Map; import org.a ...
- vs visual stdio 调试 显示指针为数组
假如有这样一个指针 int * idx16 那么要想在调试里面显示为数组并且要显示的数组元素个数为24的话,则要写成idx16,24 如下图