zoukankan      html  css  js  c++  java
  • 洛谷U140357 Seaway连续

    洛谷U140357 Seaway连续

    洛谷传送门

    题目背景

    SeawaySeawa**y最近正在学习数学的实分析。这一天,他了解到实分析中的这样一种定义:对于在实数集的子集的函数f:Dsubseteq R ightarrow Rf:D⊆R→R ,若存在常数KK,使得|f(a)-f(b)|le K imes|a-b|,forall a,bin D∣f(a)−f(b)∣≤K×∣ab∣,∀a,bD ,则称ff符合利普希茨条件(Lipshitz Continuous),对于ff最小的常数KK称为ff利普希茨常数(Lipshitz number)

    题目描述

    SeawaySeawa**y马上对于利普希茨条件产生了极大的兴趣,并对其潜心研究。他觉得LipshitzLipshit**z条件在实分析数学中的确有着非常广泛的意义。但是,同样地,其定义域的广度也造成了它具备一定的困难度。现在,SeawaySeawa**y着手对利普希茨条件进行了合理简化,产生了SeawaySeawa**y连续(Seaway Continuous)。其定义如下:

    对于一个由正整数构成的序列v[1...n]v[1...n],定义其SeawaySeawa**y连续S(v)S(v)为:对于任意整数i,jin[1,n]i,j∈[1,n],满足|v[j]-v[i]|le K imes |j-i|∣v[j]−v[i]∣≤K×∣ji∣的最小非负整数KK

    现在,给出一个长度为nn的序列v[1...n]v[1...n]和qq个询问,对于每个询问[l,r][l,r],请你求出:v[l...r]v[l...r]的所有子序列的SeawaySeawa**y连续值之和。

    输入格式

    从文件continuous.incontinuou**s.i**n中读入数据。

    第一行两个整数n,qn,q,表示序列长度和询问个数。第二行nn个数,描述vv序列。接下来的qq行,每行两个整数l,rl,r,表示每个询问区间为[l,r][l,r]。

    输出格式

    输出到文件continuous.outcontinuou**s.out中。

    对于每个询问,输出一行一个数ansans,表示v[l...r]v[l...r]的所有子序列的SeawaySeawa**y连续之和。


    命题背景:

    其实这题出出来就是奔着挨揍去的。怎么看这题都不应该放T1。

    但是我就是放了。咋的吧。

    为了防止学弟爆破,出这道题的题面让我煞费苦心。原本的Lipshitz不敢写,因为一写就被爆了。但是我充分发挥了中国人的聪明才智,变成了:利氏。

    嘿嘿。

    所以这题就变成了现在这个样子。我觉得它的思维难度完全可以评紫。但是既然大家都说比较蓝,那还是比较蓝吧。


    题解:

    u1s1,这题看起来就很搞人心态。

    上来一堆数学定义,然后又是最小又是连续,又是所有子序列都要枚举到。乖乖,暴力分都不好给啊。

    但是我还是想出来怎么给暴力了的。

    20分纯暴力枚举,n=10随便过。然后n=100,q=10的20分,暴力枚举应该也可以过,可能需要卡卡常。

    然后n=1000和n=10000的部分分是给贪心的,也就是不用暴力枚举,加个贪心来剪枝。于此同时,加数据结构比如线段树来维护,当然因为无修所以其他的数据结构也可以,大家开心就好。

    感觉部分分给的还是很多的,而且这道题冷静下来想其实也不是特别难。

    正解:数学推导+单调栈维护。

    其实这个(Lipshitz)值是啥啊,就是这个东西呀:

    [L(h)=maxlceilfrac{|h[j]-h[i]|}{|j-i|} ceil ]

    其中,(i,j)要遍历所有位置。

    这个是啥啊,这个不就是这个散点型函数的斜率么!

    于是我们对一个区间进行子区间枚举,并且在子区间再暴力枚举(i,j)。就可以暴力地得到这个东西。时间复杂度为(O(qn^4))。可以通过20pts(真是良心出题人)。

    然后思考优化。发现可以剪枝呀!

    不用枚举那么多,可以证明的一个贪心是:对于任意三个点来讲,其最大斜率绝对不可能出现在一号点和三号点之间,而只会出现在1、2,或2、3之间。

    于是先预处理出所有的(h[i+1]-h[i]),然后架一棵线段树求区间max,可以把一重(n^2)优化成(log n)。复杂度为(O(qn^2log n))。可以通过60pts。

    还能不能更优秀呢?能,可以换种思路,把问题变成:询问区间中有多少子区间是以(a[i])做最大值的((a[i]=|h[i+1]-h[i]|)

    发现这个可以用单调栈维护出左右第一个大于它的。设左右分别为(l,r),那么最后每个(a[i])对答案的贡献就是,这个点到左的距离*这个点到右的距离 *这个点的权值.

    于是我们只需要每次扫一遍即可。

    时间复杂度(O(n+qn))

    可以得满分。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define lll long long
    using namespace std;
    const int maxn=1e5+5;
    int n,q;
    int h[maxn],a[maxn];
    int st[maxn],top;
    int cnt[maxn];
    lll query(int l,int r)
    {
    	lll ret=0;
    	top=0;
    	st[0]=l-1;
    	for(int i=l;i<r;i++)
    	{
    		while(top && a[i]>a[st[top]])
    		{
    			ret+=(1ll*cnt[top]*a[st[top]]*(i-st[top]));
    			top--;
    		}
    		st[++top]=i;
    		cnt[top]=i-st[top-1];
    	}
    	while(top)
    	{
    		ret+=(1ll*cnt[top]*a[st[top]]*(r-st[top]));
    		top--;
    	}
    	return ret;
    }
    int main()
    {
    	scanf("%d%d",&n,&q);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&h[i]);
    	for(int i=1;i<n;i++)
    		a[i]=abs(h[i+1]-h[i]);
    	for(int i=1;i<=q;i++)
    	{
    		int ll,rr;
    		scanf("%d%d",&ll,&rr);
    		printf("%lld
    ",query(ll,rr));
    	}
    	return 0;
    }
    
  • 相关阅读:
    iOS项目的目录结构和开发流程
    XCode SVN设置
    iOS 登录 注册
    ios开发常用技巧
    iOS问题解答
    iOS设计模式
    iOS开发:打包应用程序
    iOS 封装
    iOS开发常用宏
    Objective-C 类,实例成员,静态变量,对象方法,类方法(静态方法),对象
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14025988.html
Copyright © 2011-2022 走看看