zoukankan      html  css  js  c++  java
  • P7115 移球游戏

    https://www.luogu.com.cn/problem/P7115

    考场上做出了70分做法

    先考虑能把一个柱子上的球做什么样的操作,有一种想法是把某一种颜色的球全部放到顶部
    具体做法大概是这样,先选择任意一个满栈 (O),和一个空栈 (E),操作:

    • 记这个要操作的栈为 (X),设 (X) 中有 (num) 个这种颜色的球
    • (H) 中最上面的 (num) 个放入 (E)
    • 对于 (X),把所有是这种颜色的球放入 (O) 中,不是的放入 (E) 中。此时 (X) 空,(E,O) 均已满
    • (E) 中最上面的 (m-num) 个放回 (X) 中,再把 (O) 中最上面的 (num) 个放回 (X)。此时对于 (X) 的操作已完成
    • (E) 中剩下的 (num) 个放回 (O),此时 (O) 已经恢复原状,(E)

    做这样一次操作的操作次数是 (2m+2num)

    由此,一种比较显然的做法就是,枚举每种颜色,把每个混乱(就是不是单色)的柱子中的这种颜色都放到顶部,然后再把他们全都提取到空栈中,就又多了一个不混乱的柱子
    然后继续枚举下一个颜色,直到所有柱子都不混乱
    在卡一卡操作次数的常数,计算的可以过 70 分(实际上ccf数据过了80分)

    对于正解,采用分治的方法
    对于颜色区间 ([l,r]),把所有 ([l,mid]) 的颜色视为同一种颜色,([mid+1,r]) 也视为同一种
    然后把 ([l,mid]) 的提升到对应柱子的顶部,然后对于每两个柱子,我们总是能令其中的一个中的所有颜色都变成 ([l,mid])([mid+1,r])
    把每个柱子都选择另一个柱子来这样做就可以了
    这样,有 (mid-l+1) 个柱子变成了颜色 ([l,mid]),另外 (r-mid) 个变成了 ([mid+1,r]),再进行递归即可
    (l=r) 时,也就完成了操作,当前柱子上的颜色统一了

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define reg register
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')y=0;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
    	return y?x:-x;
    }
    int n,m;
    int stack[55][455],top[55];
    int A[820006],B[820006],k;
    inline void putt(int a,int b){
    //		printf("%d %d
    ",a,b);
    	A[++k]=a;B[k]=b;
    	stack[b][++top[b]]=stack[a][top[a]];
    	top[a]--;
    }
    inline int cnt(int i,int p){
    	int num=0;
    	for(reg int o=1;o<=m;o++) num+=(stack[i][o]<=p);
    	return num;
    }
    void work(int l,int r,int col[]){
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	for(reg int i=1;i<=r-l+1;i++){
    		int other=i+1;
    		if(other==r-l+2) other=1;
    		int backup=i;
    		i=col[i];other=col[other];
    		int num=cnt(i,mid),dibu;
    		if(!num) continue;
    		for(reg int o=1;o<=num;o++) putt(other,n+1);
    		for(reg int o=1;o<=m;o++){
    			if(stack[i][o]<=mid){dibu=o;break;}
    		}
    		for(reg int o=m;o>=dibu;o--){
    			if(stack[i][o]<=mid) putt(i,other);
    			else putt(i,n+1);
    		}
    		for(reg int o=dibu;o<=m-num;o++) putt(n+1,i);
    		for(reg int o=m-num+1;o<=m;o++) putt(other,i);
    		for(reg int o=m-num+1;o<=m;o++) putt(n+1,other);
    		i=backup;
    	}//将所有 [l,mid] 颜色置于每个柱子的顶部
    	int col1[52],col2[52];
    	col1[0]=col2[0]=0;
    	for(reg int i=1;i<=r-l;i++){
    		int backup=i;
    		int i1=col[i+1];i=col[i];
    		int num1=cnt(i,mid),num2=cnt(i1,mid);
    		if(num1+num2>=m){
    			col1[++col1[0]]=i;
    			for(reg int o=m;o;o--) putt(i,n+1);
    			for(reg int o=m;stack[i1][o]<=mid&&o;o--) putt(i1,i);
    			for(;top[i1]<m;) putt(n+1,i1);
    			for(;top[i]<m;) putt(n+1,i);
    		}
    		else{
    			col2[++col2[0]]=i;
    			for(reg int o=m;stack[i][o]<=mid&&o;o--) putt(i,n+1);
    			for(reg int o=m;stack[i1][o]<=mid&&o;o--) putt(i1,n+1);
    			for(;top[i]<m;) putt(i1,i);
    			for(;top[i1]<m;) putt(n+1,i1);
    		}
    		i=backup;
    	}
    	if(stack[col[r-l+1]][1]<=mid) col1[++col1[0]]=col[r-l+1];
    	else col2[++col2[0]]=col[r-l+1];
    	work(l,mid,col1);work(mid+1,r,col2);
    }
    int main(){
    	n=read();m=read();
    	for(reg int i=1;i<=n;i++){
    		for(reg int j=1;j<=m;j++) stack[i][j]=read();
    		top[i]=m;
    	}
    	int col[52];
    	for(reg int i=1;i<=n;i++) col[i]=i;
    	work(1,n,col);
    	printf("%d
    ",k);
    	for(reg int i=1;i<=k;i++) printf("%d %d
    ",A[i],B[i]);
    	return 0;
    }
    
  • 相关阅读:
    特殊字符大全
    ASP執行文件下載
    在 Access 里使用查询建立 存储过程/视图, 并使用 ASP 执行
    通過windows的排定工作來執行存儲過程
    前台页面中用js取得eWebEditor的值
    IE7外觀優化
    电话订票
    在BIOS设置“扩展或板载”显卡的方法
    子窗口中操作父窗口对像(javascript)(转)
    mailto用法
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/14106351.html
Copyright © 2011-2022 走看看