首页 > 其他分享 >P10068 [CCO2023] Line Town 题解

P10068 [CCO2023] Line Town 题解

时间:2024-02-08 20:12:26浏览次数:36  
标签:Town int 题解 ll MAXN inline P10068 2i define

好题,但是感觉写起来有点屎。

题目大意

给定一个序列 \(a\),你每次可以选择 \(i \in [1,n-1]\),交换 \(a_i,a_{i+1}\),并且给 \(a_i,a_{i+1}\) 取相反数。

问你最少需要多少次交换才能使得序列非降,可能无解。

做法

首先考虑给偶数位置初始乘上 \(-1\),然后操作变成交换相邻两个数,下面提到的序列都是进行了这个操作之后的,最后需要使得:

  1. 对于奇数 \(i\),满足 \(a_i+a_{i+1} \leq 0\)。
  2. 对于偶数 \(i\),满足 \(a_i+a_{i+1} \geq 0\)。

然后发现 \(2i-1,2i\) 中必然有一个是非正数,\(2i,2i+1\) 中必然有一个非负数。

容易证明最后的序列肯定存在一个位置 \(p\) 满足:

  1. \(\forall i \in [2,p]\),\(|a_{i-1}| \geq |a_i|\),且 \(a_{i-1}\) 和 \(a_i\) 符号不同。
  2. \(\forall i\in [p+1,n-1]\),\(|a_{i}|\leq|a_{i+1}|\),且 \(a_{i+1}\) 和 \(a_i\) 符号不同。

启示我们按照绝对值大小填数。

设 \(f_{i,j\in \{0,1\},k\in \{0,1\}}\) 表示填完了绝对值 \(\geq i\) 的,目前最左边一个数符号是正还是负,最右边一个是正还是负。

考虑怎么转移。

我们将绝对值等于 \(i\) 的数拿出来,正负分开。

考虑枚举绝对值等于 \(i\) 的数中有 \(t\) 个要放在左边,剩下的放右边,贪心的去想肯定是把编号最小的放左边,编号大的放右边,所以在枚举 \(j\) 的情况下,其实放法是固定的。注意要求相邻两个数正负性不同,所以其实是正符号内部有序,负符号内部有序。

贡献可以树状数组简单计算。时间复杂度 \(O(n \log n)\)。

//code by Emissary
#include<bits/stdc++.h>

#define fi first
#define se second
#define vc vector
#define db double
#define ll long long
#define mk make_pair
#define pb push_back
#define PI pair<int,int>
#define ull unsigned long long
#define err cerr << "   -_-   " << endl
#define debug cerr << " ------------------- " << endl

#define input(x) freopen(#x".in","r",stdin)
#define output(x) freopen(#x".out","w",stdout)

#define NO puts("No")
#define YES puts("Yes")

//#define int long long

using namespace std;

namespace IO{
	inline int read(){
		int X=0, W=0; char ch=getchar();
		while(!isdigit(ch)) W|=ch=='-', ch=getchar();
		while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48), ch=getchar();
		return W?-X:X;
	}
	inline void write(ll x){
		if(x<0) x=-x, putchar('-');
		if(x>9) write(x/10);
		putchar(x%10+'0');
	}
	inline void sprint(ll x){write(x), putchar(32);}
	inline void eprint(ll x){write(x), putchar(10);}
}using namespace IO;

const int MAXN = 5e5+5;

int n, a[MAXN], tree[3][MAXN], mu[2]={-1,1}, ans[MAXN];
int tot[2], k0, k1, le[MAXN], ri[MAXN], topf, stk[MAXN], uL[MAXN][2], uR[MAXN][2];

vc<int> col[2];

ll v1[MAXN], v2[MAXN];
ll dp[2][2], g[2][2];

struct NUM{
	int v, col, id;
	inline bool friend operator < (const NUM &x, const NUM &y){
		return x.v>y.v;
	}
}num[MAXN];

inline int lowbit(int x){return x & -x;}

inline void add(int x, int v, int t){
	while(x<=n) tree[t][x]+=v, x+=lowbit(x);
	return ;
}

inline int ask(int x, int t){
	int s=0;
	while(x) s+=tree[t][x], x^=lowbit(x);
	return s;
}

inline int query(int l, int r, int t){return ask(r,t)-ask(l-1,t);}

inline void op(int l, int r){
	memset(g,127/3,sizeof g);
	col[0].clear(); col[1].clear();
	for(int i=l;i<=r;++i) col[num[i].col].pb(num[i].id), add(num[i].id,-1,0);
	for(int i=l;i<=r;++i){
		le[num[i].id]=query(1,num[i].id-1,0);
		ri[num[i].id]=query(num[i].id+1,n,0);
		}
	sort(col[0].begin(),col[0].end());
	sort(col[1].begin(),col[1].end());
	int L[2], R[2];
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			if(dp[i][j]>1ll*n*n) continue;
			ll s=0; int now=i; L[0]=L[1]=0;
			int len=col[0].size()+col[1].size();
			for(int k=1;k<=len;++k) v1[k]=v2[k]=1e18;
			for(int k=1;k<=len;++k){
				if(L[now]==col[now].size()) break;
				int c=col[now][L[now]]; L[now]++;
				v1[k]=v1[k-1]+query(c+1,n,1); add(c,1,1); stk[++topf]=c;
				now^=1; uL[k][0]=L[0], uL[k][1]=L[1];
			}
			while(topf) add(stk[topf],-1,1), --topf; now=j;
			R[0]=(int)col[0].size()-1; R[1]=(int)col[1].size()-1;
			uR[0][0]=R[0], uR[0][1]=R[1];
			for(int k=1;k<=len;++k){
				if(R[now]<0) break;
				int c=col[now][R[now]]; R[now]--;
				v2[k]=v2[k-1]+query(1,c-1,1); add(c,1,1); stk[++topf]=c;
				now^=1; uR[k][0]=R[0], uR[k][1]=R[1];
			}
			while(topf) add(stk[topf],-1,1), --topf;
			for(auto k:col[0]) s+=ri[k], add(k,1,1);
			for(auto k:col[1]) s+=ri[k], add(k,1,1);
			int A, B; now=i; L[0]=L[1]=0; ll S=0;
			for(int k=0;k<=len;++k){
				A=k&1, B=(len-k)&1;
				if(uL[k][0]-1==uR[len-k][0] && uL[k][1]-1==uR[len-k][1]) g[i^A][j^B]=min(g[i^A][j^B],dp[i][j]+s+S+v1[k]+v2[len-k]);
				if(k!=len){
					if(L[now]==col[now].size()) break;
					int c=col[now][L[now]]; L[now]++;
					now^=1; S-=query(c+1,n,2); add(c,-1,1); S+=query(1,c-1,1); add(c,1,2); stk[++topf]=c; s+=le[c]-ri[c];
				}
			}
			while(topf) add(stk[topf],-1,2), --topf;
			while(L[0]<col[0].size()) add(col[0][L[0]],-1,1), L[0]++;
			while(L[1]<col[1].size()) add(col[1][L[1]],-1,1), L[1]++;
		}
	}
	for(int i=0;i<2;++i)
		for(int j=0;j<2;++j) dp[i][j]=g[i][j];
	return ;
}

signed main(){
	n=read(); int c=0;
	for(int i=1;i<=n;++i) a[i]=read()*mu[i%2], c+=a[i]==0;
	for(int i=1;i<=n;++i){
		if(a[i]<0) num[i].col=1;
		else num[i].col=0; num[i].v=abs(a[i]); num[i].id=i;
	}
	sort(num+1,num+1+n);
	int L, R, las;
	if(n%2==0) L=R=1;
	else L=1, R=0; las=1;
	memset(dp,127/3,sizeof dp); dp[L][R]=0;
	for(int i=1;i<=n;++i) add(i,1,0);
	for(int i=2;i<=n-c;++i){
		if(num[i].v!=num[i-1].v){
			op(las,i-1);
			las=i;
		}
	}
	if(c!=n) op(las,n-c); ll ans=min(min(dp[0][0],dp[0][1]),min(dp[1][1],dp[1][0]));
	eprint(ans>1ll*n*n?-1:ans);
	return 0;
}

标签:Town,int,题解,ll,MAXN,inline,P10068,2i,define
From: https://www.cnblogs.com/OccasionalDreamer/p/18012097

相关文章

  • CF1706E 题解
    你谷题目传送门CF题目传送门题目大意给定一个\(n\)个点\(m\)条边的无向图,询问\(q\)次,每次询问会指定两个正整数\(l,r\),问要使对于\(l\leqa\leqb\leqr\)的所有\(a,b\)均有路径可以互相到达,最少需要加入前多少条边。思路考虑到每一次询问实质上就是问你在按......
  • [COCI2007-2008#1] ZAPIS 题解
    题目传送门前置知识区间型动态规划思考过程这题也算是一道很经典的问题了(?)。看见\(n\leq200\),不难想到复杂度为\(O(n^3)\)的区间型动态规划。题面中有这么一段话。空串是规则括号序列。如果\(\textttA\)是规则括号序列,那么\(\texttt{(A)[A]{A}}\)都是规则括号......
  • CF1735D Meta-set 题解
    题目大意给定\(n\)张卡牌,每张卡牌有\(k\)个属性,第\(i\)张卡牌的第\(j\)个属性为\(c_{i,j}\)。一个由\(3\)张卡牌\(x,y,z\)组成的集合被称作好的,当且仅当对于\(1\leqi\leqk\)均有\(c_{x,i}=c_{y,i}=c_{z,i}\)或者\(c_{x,i},c_{y,i},c_{z,i}\)两两不相等。......
  • CF1793E Velepin and Marketing 题解
    题目大意有\(n\)个读者,第\(i\)年他们要一起读\(k_i\)本书,每一本书至少要让一个人读,每一个人也只能读恰好一本书。如果某一个人\(j\),如果有\(a_j\)个人这一年里和他读了同一本书,那么他就会感到满足。对于所有的\(q\)组询问,每组给定一个\(k_i\),求感到满足的人数的最......
  • CF1735E House Planning 题解
    题目大意一条直线上有\(n\)个房子和两个人,房子的坐标\(d_1,d_2,d_3\dotsd_n\),以及两个人坐标为\(p_1,p_2\)。现在会告诉你两个集合\(S_1=\{|p_1-d_i|,1\leqi\leqn\}\)以及\(S_2=\{|p_2-d_i|,1\leqi\leqn\}\)。这个写法可能不是很规范,但为了美观就写成这样了。......
  • CF1847E Triangle Platinum? 题解
    感谢@swiftc管理反馈的信息,对于题目大意确定的东西进行了完善。交互题。题目大意有一个长度为\(n\)的序列\(a\)满足\(1\leqa_i\leq4\),现在你可以进行不超过\(5500\)次询问,每次询问询问三个数\(1\leqi<j<k\leqn\),你将会得到\(a_i,a_j,a_k\)构成的三角形......
  • [ABC327G] Many Good Tuple Problems 题解
    Description对于一对长度均为\(M\)且元素值在\(\left[1,N\right]\)之间的序列\((S,T)\),定义其为好的当且仅当:存在一个长度为\(N\)的\(01\)序列\(X\),使得其满足如下条件:对于任意\(i\in\left[1,M\right]\),有\(X_{S_i}\neqX_{T_i}\)。给定\(N,M\),求在......
  • CF1918G Permutation of Given 题解
    总体思路本题通过每次在已知序列中加入\(2\)个元素的方法,可以构造出满足条件的序列\(A\),这里提供一种新的构造方法。性质因为序列\(A\)中所有元素构成的可重集与序列\(B\)中所有元素构成的可重集完全相等,所以\(A\)中所有元素之和与\(B\)中所有元素之和相等。\[\s......
  • SP277 CTGAME - City Game 题解
    题目传送门前置知识单调栈解法令\(f_{i,j}(1\lei\len,1\lej\lem)\)表示从\((1,j)\)到\((i,j)\)中以\((i,j)\)结尾的均为F的子串长度,即\((i,j)\)上面可延伸的最大距离(子矩形的长)。用单调栈的第一维存储子矩形的长,第二维存储子矩形的宽。考虑依次枚举每一......
  • qoj8171 Cola 题解
    题目链接点击打开链接题目解法很牛的题!!!会不了一点令\(pref_i\)表示第\(i\)轮知道了前缀\([1,...,i]\)考虑怎样的\(pref\)序列是合法的(即采用最优策略):\(pref_0=0\)\(\forall_{i\in[0,n-1]}\;pref_i\lepref_{i+1}\)\(pref\)中\(x\)的出现次数\(\len-x-1\),因......