1 条题解

  • 0
    @ 2025-8-24 22:33:10

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar little_sheep917
    我太菜了 QvQ

    搬运于2025-08-24 22:33:10,当前版本为作者最后更新于2021-08-31 21:32:11,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    图书馆里有 nn 个书架,每个书架可以放 mm 本书。小C是一位优秀的图书管理员,所以他决定整理图书馆中的所有图书,如果可以的话,把所有图书放回它们原来的位置。他打算用下面的方法来整理图书:

    1.如果书架上的某本书的左边或右边是空的,就可以把这本书书向左或向右移动。

    2.把一本书从书架上拿起来,再放回到另一个空的位置(可以是任意一个书架)。

    可是没过多久小 C 就累了。如果他手上已经有了一本书,他就不能再移动其他的书。而且因为把书拿出来又放回去实在太麻烦了,所以小 C 希望尽可能少地将书从书架上拿起来(即步骤2)。请帮小 C 算出,他最少需要将书拿出来多少次。

    1n,m10001\leq n,m\leq 1000

    感觉做法挺奇妙的 .

    一行一行地考虑 .

    先考虑当前行和最终行出现书本相同的情况 . 此时,又分出来两种 ,有空位和无空位 .

    1. 有空位,相当于,找到一本书,再放到它原本的位置上 . 那么,要选出 kk 本书,这 kk 本书相对顺序是正确的,其他的书要根据这 kk 本书的位置放入 . 会发现,这是一个 lis 的问题 . 那么,可以 O(nlogn)O(n\log n) 地解决.
    2. 没有空位,此时分为两种情况 .
      • 当前行与目标行相同 . 无需操作 .
      • 当前行与目标行不同,如果其他书架上没有空位,则输出 -1 . 否则,将当前行中一本不位于 kk 本书中的书放到其他书架上,再将当前行排序,排完序后直接插入正确的位置,时间复杂度为 O(nlogn)O(n\log n) .

    考虑玩当前行和最终行出现书本相同的情况,下面就是不同的 .

    如果最终应该出现在第 jj 行的书出现在了第 ii 行,那么,由 iijj 连一条有向边 ,得到一个有向图 G1G_1 ;将 G1G_1 中的有向边变成无向,可以得到一个无向图 G2G_2 . 对于 G2G_2 中的每一个连通块,在 G1G_1 中可以加上一些虚构的有向边,是的其变成一个具有欧拉回路的图 .

    那么,对于这个欧拉回路,就是一个移动的方案,但是,这个方案的开始,必定是存在一个连通块中的行有一个空位 . 如果其他的行没有空位的话,那么,必定是不可行的,要输出 -1 .否则,如果连通块不存在空位,需要拿出一本书放在另一行中,然后再移动 ,代价加 11 .

    因为从当前书架拿起,放到其他书架的书必定花费代价 11 ,而且必定会放到正确的相对位置上 . 代价就是原来就同时存在与当前和最终行中的书的和 - 当前和最终行中的书的和的 lis + 在最终行但不在当前行的书的数量 . 再加上启动时可能需要的 11 代价.

    时间复杂度 : O(nmlogn)O(nm\log n)

    空间复杂度 : O(nm)O(nm)

    code

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	int res=0;
    	while(ch>='0'&&ch<='9'){
    		res=res*10+ch-'0';
    		ch=getchar();
    	}
    	return res;
    }
    inline void print(int res){
    	if(res==0){
    		putchar('0');
    		return;
    	}
    	int a[8],len=0;
    	while(res>0){
    		a[len++]=res%10;
    		res/=10;
    	}
    	for(int i=len-1;i>=0;i--)putchar(a[i]+'0');
    }
    const int inf=1e9+10;
    int n,m;
    int a[1010][1010],b[1010][1010],nu[1010*1010];
    int pos[1010*1010];
    bool ok[1010],spare=false;
    int exist[1010*1010];
    int ans=0;
    int bit[1010];
    inline void upd(int i,int val){
    	while(i<=m){
    		bit[i]=max(bit[i],val);
    		i+=i&-i;
    	}
    }
    inline int qry(int i){
    	int res=0;
    	while(i){
    		res=max(res,bit[i]);
    		i-=i&-i;
    	}
    	return res;
    }
    vector<int>v,g[1010];
    bool vis[1010];
    void dfs(int x){
    	vis[x]=true;v.push_back(x);
    	for(int i=0;i<(int)g[x].size();i++){
    		int to=g[x][i];
    		if(!vis[to])dfs(to);
    	}
    }
    int solve(int id){
    //	cout<<endl;
    //	for(int i=0;i<m;i++)cout<<a[id][i]<<" ";cout<<endl;
    //	for(int i=0;i<m;i++)cout<<b[id][i]<<" ";cout<<endl;
    	int cnt=0;
    	for(int i=0;i<m;i++)if(a[id][i]>0)nu[a[id][i]]=cnt++;
    	for(int i=0;i<=m;i++)bit[i]=0;
    	for(int i=0;i<m;i++)if(b[id][i]>0)
    		upd(nu[b[id][i]]+1,qry(nu[b[id][i]])+1);
    	int mx=0;
    	for(int i=1;i<=cnt;i++)mx=max(mx,qry(i));
    	return mx;
    }
    int na[1010],nb[1010];
    void solve(vector<int>v){
    	bool sp=false;
    	for(int i=0;i<(int)v.size();i++){
    		int id=v[i];
    		for(int j=0;j<m;j++)if(a[id][j]==0)sp=true;
    	}
    	int cnt=0;
    	for(int i=0;i<(int)v.size();i++){
    		int id=v[i];
    		for(int j=0;j<m;j++)if(a[id][j]>0)exist[a[id][j]]++,cnt++;
    		for(int j=0;j<m;j++)if(b[id][j]>0)exist[b[id][j]]++;		
    		for(int j=0;j<m;j++)na[j]=a[id][j];
    		for(int j=0;j<m;j++)nb[j]=b[id][j];
    		for(int j=0;j<m;j++)if(a[id][j]>0&&exist[a[id][j]]<2)a[id][j]=0;
    		for(int j=0;j<m;j++)if(b[id][j]>0&&exist[b[id][j]]<2)b[id][j]=0;
    		ans-=solve(id);
    		for(int j=0;j<m;j++)a[id][j]=na[j];
    		for(int j=0;j<m;j++)b[id][j]=nb[j];
    		for(int j=0;j<m;j++)if(a[id][j]>0)exist[a[id][j]]--;
    		for(int j=0;j<m;j++)if(b[id][j]>0)exist[b[id][j]]--;
    	}
    //	putchar('\n');
    	ans+=cnt;
    	if(!sp){
    		if(!spare){
    			putchar('-');
    			putchar('1');
    			exit(0);
    		}
    		else ans++;
    	}
    }
    int main(){
    //	freopen("test.txt","r",stdin);
    	n=read();m=read();
    	for(int i=0;i<n;i++)for(int j=0;j<m;j++)a[i][j]=read();
    	for(int i=0;i<n;i++)for(int j=0;j<m;j++)b[i][j]=read();
    	for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(a[i][j]==0)spare=true;
    	for(int i=0;i<n;i++){
    		bool flag=true;
    		int cnt=0;
    		for(int j=0;j<m;j++){
    			if(a[i][j]>0){
    				exist[a[i][j]]=true;
    				cnt++;
    			}
    		}
    		for(int j=0;j<m;j++){
    			if(b[i][j]>0){
    				if(!exist[b[i][j]])
    					flag=false;
    				else exist[b[i][j]]=false;
    			}
    		}
    		for(int j=0;j<m;j++){
    			if(exist[a[i][j]]){
    				flag=false;
    				exist[a[i][j]]=false;
    			}
    		}
    		if(flag){
    			ok[i]=true;
    			int tmp=cnt-solve(i);
    			ans+=tmp;
    			if(cnt==m&&tmp!=0){
    				if(!spare){					
    					putchar('-');
    					putchar('1');
    					return 0;
    				}
    				else ans++;
    			}
    		}
    	}
    //	for(int i=0;i<n;i++)print(ok[i]),putchar(' ');
    //	putchar('\n');
    	for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(a[i][j]>0&&(!ok[i]))pos[a[i][j]]=i;
    	for(int i=0;i<n;i++)for(int j=0;j<m;j++){
    		if(b[i][j]>0&&(!ok[i])&&pos[b[i][j]]!=i){
    		//	print(pos[b[i][j]]);putchar(' ');print(i);putchar('\n');
    			g[pos[b[i][j]]].push_back(i);
    			g[i].push_back(pos[b[i][j]]);
    		}
    	}
    	for(int i=0;i<n;i++)if((!ok[i])&&(!vis[i])){
    		v.clear();
    		dfs(i);
    	//	for(int j=0;j<(int)v.size();j++)print(v[j]),putchar(' ');
    		solve(v);
    	}	
    	print(ans);
    	return 0;
    }
    /*inline? ll or int? size? min max?*/
    
    
    • 1

    信息

    ID
    7129
    时间
    1000ms
    内存
    64MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者