POLICE(LCS转LIS 并查集)

题意:

n个书架,每个m个位置,要求变到目标状态。

有两种操作:在一个书架内让一本书左右移动;拿起一本书放到任意空白位置。

求最少拿起次数。

解析:

书分两种:不需要拿起和需要拿起。

不需要拿起:求出原状态和目标状态的最长公共子序列(LCS)
需要拿起:手模后发现只要需要交换的几行内(并查集得到)有空格,那么答案就是 b o o k l c s \sum_{book}-\sum_{|lcs|} 。否则需要额外的一步。

LCS的时间复杂度是 O ( N 2 ) O(N^2) ,由于这里标号唯一,所以可以用B数组的位置来标记A数组,求A数组的LIS,单次时间复杂度降低为 O ( N l o g N ) O(NlogN)

特判:

全非0且有不同时-1。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2020-07-16-13.15.48
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test() {
    cerr<<"\n";
}
template<typename T,typename... Args>void test(T x,Args... args) {
    cerr<<"> "<<x<<" ";
    test(args...);
}
const LL mod=1e9+7;
const int maxn=1e6+9;
const int inf=0x3f3f3f3f;
namespace Fast_IO{ //orz laofu
    const int MAXL((1 << 18) + 1);int iof, iotp;
    char ioif[MAXL], *ioiS, *ioiT, ioof[MAXL],*iooS=ioof,*iooT=ioof+MAXL-1,ioc,iost[55];
    char Getchar(){
        if (ioiS == ioiT){
            ioiS=ioif;ioiT=ioiS+fread(ioif,1,MAXL,stdin);return (ioiS == ioiT ? EOF : *ioiS++);
        }else return (*ioiS++);
    }
    void Write(){fwrite(ioof,1,iooS-ioof,stdout);iooS=ioof;}
    void Putchar(char x){*iooS++ = x;if (iooS == iooT)Write();}
    inline int read(){
        int x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
		if(ioc==EOF)exit(0);
        for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
    }
    inline long long read_ll(){
        long long x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
		if(ioc==EOF)exit(0);
        for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
    }
    template <class Int>void Print(Int x, char ch = '\0'){
        if(!x)Putchar('0');if(x<0)Putchar('-'),x=-x;while(x)iost[++iotp]=x%10+'0',x/=10;
        while(iotp)Putchar(iost[iotp--]);if (ch)Putchar(ch);
    }
    void Getstr(char *s, int &l){
        for(ioc=Getchar();ioc==' '||ioc=='\n'||ioc=='\t';)ioc=Getchar();
		if(ioc==EOF)exit(0);
        for(l=0;!(ioc==' '||ioc=='\n'||ioc=='\t'||ioc==EOF);ioc=Getchar())s[l++]=ioc;s[l] = 0;
    }
    void Putstr(const char *s){for(int i=0,n=strlen(s);i<n;++i)Putchar(s[i]);}
} // namespace Fast_IO
using namespace Fast_IO;
#define rd read()
/*_________________________________________________________begin*/

pill pb[maxn];
int a[1009][1009],b[1009][1009];
int arr[1009];

int sta[1009];
int LIS(int *a,int n) {
    if(n==0)
        return 0;
    int top=1;
    sta[1]=a[1];
    rep(i,2,n) {
        int pos=lower_bound(sta+1,sta+1+top,a[i])-sta;
        sta[pos]=a[i];
        if(pos>top) {
            assert(top==pos-1);
            top=pos;
        }
    }
    return top;
}

int fa[1009];
int siz[1009];
bool have[1009];
bool ch[1009];
int fin(int a,int dep=0) {
    assert(dep<=1000);
    return fa[a]==a?a:fa[a]=fin(fa[a],dep+1);
}
void link(int a,int b) {
    int f1=fin(a),f2=fin(b);
    if(f1!=f2) {
        if(siz[f1]>siz[f2])
            swap(f1,f2);
        fa[f1]=f2;
        siz[f2]+=siz[f1];
        if(ch[f1])
            ch[f2]=1;
        if(have[f1])
            have[f2]=1;
    }
}

int main() {
    int n=rd,m=rd;
    bool _0=0,_dis=0;
    rep(i,1,n)rep(j,1,m) {
        a[i][j]=rd;
        if(a[i][j]==0)
            _0=1;
    }
    rep(i,1,n)rep(j,1,m) {
        b[i][j]=rd;
        if(a[i][j]!=b[i][j])
            _dis=1;
        if(b[i][j]) {
            pb[b[i][j]]= {i,j};
        }
    }
    if(!_0&&_dis) {
        puts("-1");
        return 0;
    }

    int ans=0;

    rep(i,1,n) {
        rep(j,1,m) {
            if(a[i][j])
                ans++;
        }
        int cnt=0;
        rep(j,1,m) {
            if(a[i][j]&&pb[a[i][j]].fi==i) {
                arr[++cnt]=pb[a[i][j]].se;
            }
        }
        int lis=LIS(arr,cnt);
        if(lis!=cnt)
            ch[i]=1;
        ans-=lis;
    }

    rep(i,1,n) {
        fa[i]=i;
        siz[i]=1;
        rep(j,1,m) {
            if(a[i][j]==0) {
                have[i]=1;
                break;
            }
        }
    }
    rep(i,1,n) {
        rep(j,1,m) {
            if(a[i][j]&&pb[a[i][j]].fi!=i) {
                assert(pb[a[i][j]].fi<=n && pb[a[i][j]].fi>=1);
                link(i,pb[a[i][j]].fi);
            }
        }
    }

    rep(i,1,n) {
        if(fin(i)==i&&!have[i]&&ch[i]) {
            ans++;
        }
    }

    printf("%d\n",ans);

    return 0;
}

/*_________________________________________________________end*/

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/107385986