【构造】Codeforces 1025E Colored Cubes

分析:

很有趣(du)的一道题目啊。。。

构造法很简单,首先,对原序列按x坐标排序,设第i个位置排序后的序号为idiidi然后把每个位置(xi,yi)(xi,yi)平移到(idi,yi)(idi,yi)。这样只需要在yiyi这条线上平移,很容易发现这是不可能矛盾的。

现在我们让每个格子都有一个不同的横坐标xixi,说明每一列上最多只有一个格子。这时就可以直接把(idi,yi)(idi,yi)的格子移动到(idi,i)(idi,i)去,全部做完后,再把所有(idi,i)(idi,i)移动到(i,i)(i,i)去。

后面两步都因为某一坐标唯一,所以绝对合法(不会撞在一起)。

然后对目标状态再做一次,输出答案把这部分反向就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 10810
#define y1 chenchunhua
using namespace std;
typedef long long ll;
int n,m;
struct node{
    int x,y;
    int id;
    bool operator <(const node&a) const {
        if(x==a.x)
            return y<a.y;
        return x<a.x;
    }
}p[MAXN];
pair<int,int> ansf[MAXN],anst[MAXN];
int move(int top,int x0,int y0,int x1,int y1){
    while(x0!=x1){
        int xx0=x0;
        if(x1<x0)
            x0--;
        else
            x0++;
        ansf[++top]=make_pair(xx0,y0);anst[top]=make_pair(x0,y0);
    }
    while(y0!=y1){
        int yy0=y0;
        if(y1<y0)
            y0--;
        else
            y0++;
        ansf[++top]=make_pair(x0,yy0);anst[top]=make_pair(x0,y0);   
    }
    return top;
}
int solve(int top){
    sort(p+1,p+1+m);
    for(int i=1;i<=m;i++){
        if(i<p[i].x){
            top=move(top,p[i].x,p[i].y,i,p[i].y);   
            p[i].x=i;
        }
    }
    for(int i=m;i>=1;i--){
        top=move(top,p[i].x,p[i].y,i,p[i].y);   
        p[i].x=i;
    }
    for(int i=1;i<=m;i++){
        top=move(top,p[i].x,p[i].y,p[i].x,p[i].id);
        p[i].y=p[i].id; 
    }
    for(int i=1;i<=m;i++){
        top=move(top,p[i].x,p[i].y,p[i].id,p[i].y);
        p[i].x=p[i].id; 
    }
    return top;
}
int main(){
    SF("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        SF("%d%d",&p[i].x,&p[i].y);
        p[i].id=i;
    }
    int cnt=solve(0);
    for(int i=1;i<=m;i++){
        SF("%d%d",&p[i].x,&p[i].y);
        p[i].id=i;
    }
    int cnt1=solve(cnt);
    PF("%d\n",cnt1);
    for(int i=1;i<=cnt;i++)
        PF("%d %d %d %d\n",ansf[i].first,ansf[i].second,anst[i].first,anst[i].second);
    for(int i=cnt1;i>cnt;i--)
        PF("%d %d %d %d\n",anst[i].first,anst[i].second,ansf[i].first,ansf[i].second);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值