AtCoder - arc120_c Swaps 2(思维+线段树+模拟)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder - arc120_c Swaps 2(思维+线段树+模拟)相关的知识,希望对你有一定的参考价值。
题目链接:点击查看
题目大意:给出一个序列 a a a,问能否经过有限此操作使其变成 b b b,每次操作分为三步:
- 选择一个 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)
- a i + + a_i ++ ai++(交换后的)
- 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 i−1 的时候, a i a_i ai 变成了 a i + 1 a_i+1 ai+1,当到达 i − 1 i-1 i−1 的位置时,我们维护的贡献 ( a i + 1 ) + ( i − 1 ) = a i + i (a_i+1)+(i-1)=a_i+i (ai+1)+(i−1)=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 082E - ConvexScore