zoukankan      html  css  js  c++  java
  • CF360B

    本题解是 CF360B(nleq 2 imes10^5) 加强版。

    一开始看到这题难度 2000,那完蛋了啊,我连 2000 的题都不会做了/ll。然后发现数据范围才 (2000)/xk。


    答案 (x) 显然有单调性,先二分起来。

    考虑固定那些没有被改变的柱子。那么不难发现,一个没有被改变的柱子序列合法,当且仅当任意一个相邻对 (i,j) 都满足 (|a_i-a_j|leq (j-i)x)。然后考虑一个 DP,求出最少需要改变多少个柱子,即最多保留多少个柱子。

    我们考虑 (dp_i) 为考虑到 (i)(i) 保留,的最少的改变的柱子数。目标显然是 (left[maxlimits_{i=1}^n{dp_i+n-i}leq m ight])

    考虑转移。显然有一个平方的转移,就是对于每个 (i) 暴力枚举它前面的决策 (j) 然后判一下比一下。这样总复杂度平方对数,原来的弱题就做完了。就这也配 2000?我 tm 直接秒切(((((

    考虑优化。对于决策 (j),合法条件是 (|a_i-a_j|leq (i-j)x),更新式是 (dp_j+i-j-1)。那显然可以把更新式拆成 ((dp_j-j)+(i-1)),于是只要找到 (dp_j-j) 最小的合法决策即可。然后合法条件里有个绝对值,比较讨厌,考虑将它拆成 (a_igeq a_j,a_i-ixleq a_j-jx)(a_i<a_j,a_i+ixgeq a_j+jx)。这样的话,考虑将「或」字两边的分别考虑,分别二维数点,这样总复杂度线性三次对数,会爆炸。我们需要一个线性二次对数或以下的算法。

    注意到,如果最 primitive 的合法条件的 (leq) 改成 (geq),那么就很容易想到线性二次对数的算法:因为 (a_igeq a_j) 所对应的不等式和 (a_i<a_j) 所对应的不等式,它要满足就显然只会满足真实的 (a_i,a_j) 大小情况对应的那个。那就很好办,直接忽略 (a_i,a_j) 的大小关系,把两个不等式对的并一下即可。但是该题是 (leq),如果并的话,那就每个决策都一定满足假的那个大小关系所对的不等式,那就每个决策都是合法的了……而如果把不符合的,也就是 (geq) 的给不算的话,那又无法撤销。事实上 (leq) 就是不能像 (geq) 那样顺利的。

    我们考虑将「或」字改成「且」字,那就是可以像 (geq) 那样将 (a_i,a_j) 大小关系去掉的。那就可以表示成 ([a_j-jx,a_j+jx]subseteq[a_i-ix,a_i+ix])(这直接做还是需要二维数点的)。不过注意到这里的一个特殊的性质:对于 (i<j)(i) 的区间大小一定比 (j) 的区间大小小。这也就说明,我们原来是找那些 (j<i) 的满足这个条件的 (j),现在可以直接无视 (j<i) 了,因为 (j>i) 的话,(j) 的区间就更大,就不可能包含于 (i) 的区间了。于是可以调整一下 DP 顺序,将左端点排序,这样依然可以保证无后效性。这样一来,左端点这一维就不需要考虑了,于是变成一维数点了。就随便离散化 BIT 即可,小常数线性二次对数。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define pb push_back
    const int inf=0x3f3f3f3f3f3f3f3f;
    int lowbit(int x){return x&-x;}
    void read(int &x){
    	x=0;char c=getchar();bool ne=false;
    	while(!isdigit(c))ne|=c=='-',c=getchar();
    	while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	if(ne)x=-x;
    }
    const int N=200000;
    int n,m;
    int a[N+1];
    int dp[N+1];
    struct range{
    	int l,r,id;
    	range(int _l=0,int _r=0,int _id=0){l=_l,r=_r,id=_id;}
    }rg[N+1];
    bool cmp(range x,range y){
    	if(x.l!=y.l)return x.l>y.l;
    	return x.r<y.r;
    }
    vector<int> nums;
    void discrete(){
    	sort(nums.begin(),nums.end());
    	nums.resize(unique(nums.begin(),nums.end())-nums.begin());
    }
    struct bitree{
    	int mn[N+1];
    	void init(){memset(mn,0x3f,sizeof(mn));}
    	void chkmn(int x,int v){
    		while(x<=n)mn[x]=min(mn[x],v),x+=lowbit(x);
    	}
    	int Mn(int x){
    		int res=inf;
    		while(x)res=min(res,mn[x]),x-=lowbit(x);
    		return res;
    	}
    }bit;
    bool chk(int x){
    	nums.clear();
    	for(int i=1;i<=n;i++)rg[i]=range(a[i]-i*x,a[i]+i*x,i),nums.pb(a[i]+i*x);
    	discrete();
    	sort(rg+1,rg+n+1,cmp);
    	bit.init();
    	for(int i=1;i<=n;i++){
    		int fd=lower_bound(nums.begin(),nums.end(),rg[i].r)-nums.begin()+1;
    		dp[rg[i].id]=min(rg[i].id-1,bit.Mn(fd)+rg[i].id-1);
    		if(dp[rg[i].id]+n-rg[i].id<=m)return true;
    		bit.chkmn(fd,dp[rg[i].id]-rg[i].id);
    	}
    	return false;
    }
    signed main(){
    //	freopen("a.in","r",stdin);freopen("a.out","w",stdout); 
    	read(n);read(m);
    	for(int i=1;i<=n;i++)read(a[i]);
    	int ans=1e10;
    	for(int i=34;~i;i--)if(ans-(1ll<<i)>=0&&chk(ans-(1ll<<i)))ans-=1ll<<i;
    	cout<<ans<<"
    ";
    	return 0;
    }
    
    珍爱生命,远离抄袭!
  • 相关阅读:
    代理服务器的原理及用法
    [Web前端] 给li设置float浮动属性之后,无法撑开外层ul的问题。
    [Web 前端] react-router4-0中文文档
    [Web 前端] inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移
    [Web 前端] React Js img 图片显示默认 占位符
    [Web 前端] React高级教程(es6)——(2)对于Refs最新变动的理解
    [Web 前端] 你不知道的 React Router 4
    [Web 前端] React-router4简约教程
    [Web 前端] React Router v4 入坑指南
    [Web 前端] 前端频道之团队维护、聚合、订阅
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/strengthened-cf360b.html
Copyright © 2011-2022 走看看