AtCoder - arc120_c Swaps 2(思维+线段树+模拟)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder - arc120_c Swaps 2(思维+线段树+模拟)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个序列 a a a,问能否经过有限此操作使其变成 b b b,每次操作分为三步:

  1. 选择一个 i i i,满足 i + 1 < = n i+1<=n i+1<=n,然后 s w a p ( a i , a i + 1 ) swap(a_i,a_{i+1}) swap(ai,ai+1)
  2. a i + + a_i ++ ai++(交换后的)
  3. a i + 1 − − a_{i+1}-- ai+1(交换后的)

如果有解,输出最小操作次数

题目分析:思维点+固定模型的题目,有个结论是,题目有解的充分必要条件是,当且仅当 a a a 数列的每个数值都加上 i i i 所组成的新的集合,需要与 b b b 数列的每个数值都加上 i i i 后的集合相等。简单来说,集合 { a 1 + 1 , a 2 + 2 , . . . , a n + n } \\{ a_1+1,a_2+2,...,a_n+n\\} {a1+1,a2+2,...,an+n} 要与 { b 1 + 1 , b 2 + 2 , . . . , b n + n } \\{b_1+1,b_2+2,...,b_n+n\\} {b1+1,b2+2,...,bn+n} 相等,注意这里的集合类似于 S T L STL STL 中的 s e t set set

为什么这样是可行的呢,考虑第 i i i 个位置原本我们维护的是 a i + i a_i+i ai+i,当其交换到达 i − 1 i-1 i1 的时候, a i a_i ai 变成了 a i + 1 a_i+1 ai+1,当到达 i − 1 i-1 i1 的位置时,我们维护的贡献 ( a i + 1 ) + ( i − 1 ) = a i + i (a_i+1)+(i-1)=a_i+i (ai+1)+(i1)=ai+i 并没有发生改变

同理可证 i i i 变成 i + 1 i+1 i+1 时贡献不变

这样问题就转换为了,数列 a a a b b b 变成 a i + i a_i+i ai+i b i + i b_i+i bi+i 后,每次可以交换相邻的两个数字,问最少需要操作多少次可以使其相等

这样就转换成下面这个题目的模型了:
传送门

代码:

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
map<int,vector<int>>node;
map<int,int>cnt;
int a[N],b[N];
struct Node {
	int l,r,lazy;
}tree[N<<2];
void build(int k,int l,int r) {
	tree[k]={l,r,0};
	if(l==r) {
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}
void update(int k,int l,int r,int val) {
	if(l>r) {
		return;
	}
	if(tree[k].l>r||tree[k].r<l) {
		return;
	}
	if(tree[k].l>=l&&tree[k].r<=r) {
		tree[k].lazy+=val;
		return;
	}
	update(k<<1,l,r,val);
	update(k<<1|1,l,r,val);
}
int query(int k,int pos) {
	if(tree[k].l==tree[k].r) {
		return pos+tree[k].lazy;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(pos<=mid) {
		return query(k<<1,pos)+tree[k].lazy;
	} else {
		return query(k<<1|1,pos)+tree[k].lazy;
	}
}
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n;
	read(n);
	for(int i=1;i<=n;i++) {
		read(a[i]);
		a[i]+=i;
		cnt[a[i]]++;
	}
	for(int i=1;i<=n;i++) {
		read(b[i]);
		b[i]+=i;
		cnt[b[i]]--;
	}
	for(auto it:cnt) {
		if(it.second) {
			return 0*puts("-1");
		}
	}
	build(1,1,n);
	for(int i=1;i<=n;i++) {
		node[a[i]].push_back(i);
	}
	LL ans=0;
	for(int i=1;i<=n;i++) {
		int to=b[i];
		int pos=node[to][cnt[to]];
		ans+=query(1,pos)-1;
		update(1,pos+1,n,-1);
		cnt[to]++;
	}
	cout<<ans<<endl;
	return 0;
}

以上是关于AtCoder - arc120_c Swaps 2(思维+线段树+模拟)的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder ARC 076E - Connected?

AtCoder ARC 082E - ConvexScore

Atcoder ARC101 E 树dp

AtCoder ARC 076D - Built?

AtCoder Beginner Contest 120 解题报告

arc096_f Sweet Alchemy