UPC——Swap (LCS转为LIS)

LIS:传送门

问题 C: Swap

时间限制: 10 Sec 内存限制: 128 MB

题目描述
如果你需要移动一样东西,显然接触或者使用磁场电场之类的可以解决。但是有没有办法进行超越距离的随心所欲的移动?
对于物体或者文字进行超距离移动一直是人类的梦想,有一天这个难题终于被我们的大牛解决了!他现在需要的就是整理数列。数列就是所谓的写在纸上或者在电脑品目上的数列…
整理数列需要一个叫做swap的操作,swap操作就是指大牛通过超距离的控制把数列中的某一位直接插入某两位的中间或者数列的开始或者终止的操作。这个操作的关键在于超距离控制,显然这种事情不能干太多次,不但降RP,而且很耗体力。你的任务就是从初始状态到目标状态所需要做swap的最少次数。

输入
三行,第一行一个整数 n(n<600000)
第二行,n 个整数(1-n),表示初始数列。
第三行,n 个整数(1-n),表示目标数列。
保证整数不重复。

输出
一行 表示最少swap次数。
样例输入 Copy
10
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
样例输出 Copy
9

题意:

​ 给定两个1~n的全排列a,b,问最少要经过多少次swap操作能够使得a变为b。其中swap操作表示可以把任意一个数插到任意位置。

思路:

​ 很容易想到的是,对于a和b的LCS,我们可以直接保留,然后把剩下的插到对应位置即可,这样答案就是n-LCS。求LCS的复杂度是O(n^2),对于此题显然行不通。

​ 优化就是将LCS转化为LIS问题,原理

在这里插入图片描述

代码:

#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
//#include<bits/stdc++.h>
#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<unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll>PLL;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
#define I_int ll
#define modl 19260817*19890604-19491001
#define x first
#define y second
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
char F[200];
inline void out(I_int x) {
    if (x == 0) return (void) (putchar('0'));
    I_int tmp = x > 0 ? x : -x;
    if (x < 0) putchar('-');
    int cnt = 0;
    while (tmp > 0) {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0) putchar(F[--cnt]);
    //cout<<" ";
}
ll ksm(ll a,ll b,ll p){ll res=1;while(b){if(b&1)res=res*a%p;a=a*a%p;b>>=1;}return res;}
const int inf=0x3f3f3f3f,mod=1e9+7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn=6e5+100,maxm=3e6+7;
 
ll a[maxn],b[maxn],dp[maxn];
int cnt=0;
ll q[maxn];
 
int Find(int x){
    int l=1,r=cnt;
    while(l<r){
        int mid=(l+r)>>1;
        if(q[mid]>=x) r=mid;
        else l=mid+1;
    }
    return l;
}
 
int main(){
    int n=read();
    for(int i=1;i<=n;i++){
        int tmp=read();
        a[tmp]=i;
    }
    for(int i=1;i<=n;i++){
        int tmp=read();
        b[i]=a[tmp];
    }
    q[++cnt]=b[1];
    for(int i=2;i<=n;i++)
        if(b[i]>q[cnt]) q[++cnt]=b[i];
        else{
            int tmp=Find(b[i]);
            q[tmp]=b[i];
        }
    out(n-cnt);
    return 0;
}

类似题:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆沙睡不醒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值