首页 > 其他分享 >AT_abc283_f [ABC283F] Permutation Distance 题解

AT_abc283_f [ABC283F] Permutation Distance 题解

时间:2024-03-07 13:45:06浏览次数:27  
标签:Distance ch 树状 int 题解 ABC283F il auto define

分析

分类讨论。

对 \(|p_i-p_j|+|i-j|\) 分类讨论,有:

  1. \((p_i+i)-(p_j+j)\),\(p_i>p_j \land i>j\)。
  2. \(-(p_i-i)+(p_j-j)\),\(p_i<p_j \land i>j\)。
  3. \((p_i-i)-(p_j-j)\),\(p_i>p_j \land i<j\)。
  4. \(-(p_i+i)+(p_j+j)\),\(p_i<p_j \land i<j\)。

然后用树状数组跑取最小值就行了。可以开两个树状数组,\(1,3\) 情况一个;\(2,4\) 情况一个。因为要使 \(d_i\) 小,而在式子的左半部分一定时,\(1,3\) 情况的右半部分都是减一个值,所以第一个树状数组维护最大值;\(2,4\) 情况的右半部分都是加一个值,所以第二个树状数组维护最小值。最后 \(1,2\) 情况正着枚举 \(i\),\(2,4\) 情况倒着枚举 \(i\) 即可。复杂度 \(O(n \log n)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline
#define pii pair<int,int>
#define x first
#define y second
#define gc getchar()
#define rd read()
#define debug() puts("------------")

namespace yzqwq{
	il int read(){
		int x=0,f=1;char ch=gc;
		while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc;}
		while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
		return x*f;
	}
	il int qmi(int a,int b,int p){
		int ans=1;
		while(b){
			if(b&1) ans=ans*a%p;
			a=a*a%p,b>>=1;
		}
		return ans;
	}
	il auto max(auto a,auto b){return (a>b?a:b);}
	il auto min(auto a,auto b){return (a<b?a:b);}
	il int gcd(int a,int b){
		if(!b) return a;
		return gcd(b,a%b);
	}
	il int lcm(int a,int b){
		return a/gcd(a,b)*b;
	}
	il void exgcd(int a,int b,int &x,int &y){
		if(!b) return x=1,y=0,void(0);
		exgcd(b,a%b,x,y);
		int t=x;
		x=y,y=t-a/b*x;
		return ;
	}
	mt19937 rnd(time(0));
}
using namespace yzqwq;

const int N=2e5+10;
int n,p[N],d[N],s[N];
int tr1[N],tr2[N];

il void add1(int x,int y){
	while(x<=n) tr1[x]=max(tr1[x],y),x+=x&(-x);
	return ;
}
int query1(int x){
	int Max=-1e18;
	while(x) Max=max(Max,tr1[x]),x-=x&(-x);
	return Max;
}
il void add2(int x,int y){
	while(x) tr2[x]=min(tr2[x],y),x-=x&(-x);
	return ;
}
int query2(int x){
	int Min=1e18;
	while(x<=n) Min=min(Min,tr2[x]),x+=x&(-x);
	return Min;
}
il void solve(){
	n=rd;
	for(re int i=1;i<=n;++i) p[i]=rd,d[i]=1e18;
	for(re int i=1;i<=n;++i) tr1[i]=-1e18,tr2[i]=1e18;
	for(re int i=1;i<=n;++i){
		d[i]=min(d[i],(p[i]+i)-query1(p[i]));
		add1(p[i],p[i]+i);
		d[i]=min(d[i],-(p[i]-i)+query2(p[i]));
		add2(p[i],p[i]-i);	
	}
	for(re int i=1;i<=n;++i) tr1[i]=-1e18,tr2[i]=1e18;
	for(re int i=n;i>=1;--i){
		d[i]=min(d[i],(p[i]-i)-query1(p[i]));
		add1(p[i],p[i]-i);
		d[i]=min(d[i],-(p[i]+i)+query2(p[i]));
		add2(p[i],p[i]+i);
	}
	for(re int i=1;i<=n;++i) printf("%lld ",d[i]);
	return ;
}

signed main(){
	int t=1;while(t--)
	solve();
	return 0;
}
/*
1. (p[i]+i)-(p[j]+j) p[i]>p[j]^i>j
2. -(p[i]-i)+(p[j]-j) p[i]<p[j]^i>j
3. (p[i]-i)-(p[j]-j) p[i]>p[j]^i<j
4. -(p[i]+i)+(p[j]+j) p[i]<p[j]^i<j
*/

标签:Distance,ch,树状,int,题解,ABC283F,il,auto,define
From: https://www.cnblogs.com/harmisyz/p/18058728

相关文章

  • CF38E Let's Go Rolling! 题解
    分析考虑DP。因为\(n\le3000\),我们可以直接枚举插针的位置。定义状态函数\(f_i\)表示在从左往右第\(i\)个小球的位置上插针的最小花费。枚举该小球右边第一个插针的位置,则\(i\)到\(j-1\)的小球都会滚到小球\(i\)的位置。代价为\(\sum\limits_{k=i}^{j-1}x_k-x_i......
  • P6390 [COCI2007-2008#4] POKLON 题解
    感谢@\(\color{#AEF}{\texttt{CelestialCyan}}\)大神对我的骚扰帮助。分析一眼DP。对于求最大满足条件区间数,我们定义状态函数\(\mathit{f}_{i}\)表示在第\(1\)到\(i\)个区间中选择,且必选第\(i\)个区间能够得到的最大长度。有转移方程:\(\mathit{f}_{i}=\max\{f[j]|......
  • UVA13095 Tobby and Query 题解
    分析一眼莫队(虽然通过这题的范围显然看出出题人用的不是莫队)。我们定义\(\mathit{cnt}_{i}\)表示数字\(i\)出现的次数。在指针的拓展增加\(x\)时,若有\(\mathit{cnt}_{x}+1=1\),则表示在在这个区间里,\(x\)是第一次出现的,我们可以将答案加\(1\);在指针的收缩减去\(x\)时,......
  • P5017题解
    前言做这道题,首先要了解\(dp\)。\(dp\)一般有三个步骤(个人理解):根据题意确定状态。根据状态的定义推出状态转移方程,一般有两种:填表法和刷表法。填表法就是普通\(dp\),用前面的状态转移到现在的状态,例:\(f[i]=f[i-1]+a[i]\)。刷表法就是在现有的基础上(\(f[i]\)已知),去推出\(f[......
  • SP20848 IGAME - Interesting Game 题解
    分析数位DP一眼题。对于一个\(k\)位的数\(s\),我们不妨将其看做由数字\(s_1,s_2,s_3,\dots,s_k\)这\(k\)个数字拼接起来的。而题意是每个人可以将\(s_1,s_2,s_3,\dots,s_k\)中的任意一个减去任意数字,保证不减去\(0\)且结果\(\ge0\)。显然,在我们将这\(k\)个数看......
  • AT_abc216_g [ABC216G] 01Sequence 题解
    分析一道差分约束题。我们令\(\mathit{sum}_{i}\)表示\(1\)到\(i\)中,\(1\)的数量,根据题意可得:\(\mathit{sum}_{l_i-1}+x_i\le\mathit{sum}_{r_i}\)\(\mathit{sum}_{l+1}+(-1)\le\mathit{sum}_{l}\)\(\mathit{sum}_{l}+0\le\mathit{sum}_{l+1}\)因为我们要尽......
  • CF1066E 题解
    Solution首先不难想到计算\(a\)的每一位对答案产生的贡献,然后题目告诉我们\(b\)每次会往右移一位,然后结合样例可以发现:对于\(a\)的第\(i\)位,能与其产生贡献的条件是:\(a_i=1\)且\(b_j=1(i\leqj)\),对答案的贡献不难想出即为\(2^{i-1}\times\sum\limits_{j=i}^{m}b_j......
  • AT_abl_e Replace Digits 题解
    分析线段树模板题。维护一个区间\([l,r]\)中\(\sum\limits_{i=l}^r10^{n-i}\)的答案。将某个区间\([l,r]\)全部修改成\(x\)之后的表示的数就是\(x\times(\sum\limits_{i=l}^r10^{n-i})\)。区间修改可以用线段树,用快速幂或者预处理弄出来\(10^x\),建树的时候就能把每......
  • AT_abl_d Flat Subsequence 题解
    分析线段树模板题。一眼DP。定义状态函数\(\mathit{f}_i\)表示前\(i\)个数中,必选\(\mathit{A}_i\)时\(B\)的最大长度。则有转移方程:\(\mathit{f}_i=\max\{f_j|((1\lej\lei-1)\land(-k\leA_i-A_j\lek))\}+1\)。答案就是\(\max\limits_{i=1}^{n}\mathit{f}_i......
  • CF808E 题解
    很好的一道分类讨论题。观察数据范围,\(w\leq3\),不难想到,将\(w\)分为\(1,2,3\)种情况,如果直接贪心选会不难发现是错的。但是如果\(w\)的值只有\(2\)种,就像\(w=1/2\)的情况,将\(w=1/2\)的数据按价值排序,最后枚举每种选多少即可。但是\(w=3\)就会显得难以处理,需要讨......