[测试题]钦点

钦点
 
问题描述
之所以续走的那些香港记者,是因为他们掌握了长者钦点董先生的关键证据,现在这份证
据落到了你的手里。
这份文件是一个 n × m 的矩形,矩形内每一个元素是一个字符串。这份文件经过了 q 次加
密,每次加密是交换两个长宽分别相等的矩形,由于长者有点老花眼,所以他加密的时候两个矩
形间任意一对元素曼哈顿距离大于 1。
由于好奇,你开始解密这份文件,方便起见,加密操作已经倒序给你,你只要按顺序操作一
遍便能解密。
当你破解完这个文件,你会发现你的生命少了做这道题的时间。

输入格式
输入文件名为 appoint.in 
第一行,三个整数 n; m; q。
接下来的 n 行,每行 m 个非空字符串,串与串之间用一个空格隔开。
接下来的 q 行,每行六个整数 x1; y1; x2; y2; l; c 表示两个矩形的左上角和矩形的长宽 (l 对
应 x,c 对应 y)。

输出格式
输出文件名为 appoint.out。
n 行,每行 m 个非空字符串,串与串之间用一个空格隔开。表示解密后的文件。

样例输入

4 4 2
a a b b
a a b b
c c d d
c c d d
1 1 3 3 2 2
3 1 1 3 2 2

样例输出

d d c c
d d c c
b b a a
b b a a


数据规模与约定
设字符串总长为 jSj。
对于前 30% 的数据,保证 jSj ≤ n × m。
对于前 60% 的数据,保证 n; m ≤ 100。
对于 100% 的数据,保证 n; m ≤ 1000; q ≤ 5000; jSj ≤ 107。 
题解:
用链表,对于每一个节点,d[i]表示它下方的点的编号,r[i]表示它右方点的编号。
因为每次调换区域时矩形内部的相对关系没有变化,所以不需要对矩形内部的链表进行调整。
每次调换时只要将矩形四个方向的点的链表交换即可。(详见代码)
另外注意每次查找当前位置的点,一定要通过当前链表来查找。(代码中的pos函数)而不能用坐标直接访问。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
template<typename T>void read(T &x)
{
    x=0;char c=getchar();
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())x=x*10+c-'0';
}
int n,m,q,sum[1000005],r[1000005],d[1000005],a[1005][1005];
char ch[10000005];
int pos(int down,int right)
{
    int x=0;
    while(down--)x=d[x];
    while(right--)x=r[x];
    return x;
}
int main()
{
    freopen("appoint.in","r",stdin);
    freopen("appoint.out","w",stdout);
    int i,j,k;
    int x1,x2,y1,y2,xx,yy,p1,p2;
    read(n);read(m);read(q);
    for(i=1;i<=n*m;i++)
    {
        scanf("%s",ch+sum[i-1]+1);
        sum[i]=sum[i-1]+strlen(ch+sum[i-1]+1);
    }
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            a[i][j]=(i-1)*m+j;
    int tot=n*m;
    for(i=0;i<=n+1;i++)
        for(j=0;j<=m+1;j++)
            if((i||j)&&!a[i][j])a[i][j]=++tot;
    for(i=0;i<=n;i++)
        for(j=0;j<=m;j++)
            r[a[i][j]]=a[i][j+1],
            d[a[i][j]]=a[i+1][j];
    while(q--)
    {
        read(x1);read(y1);read(x2);read(y2);read(xx);read(yy);
        int pos1=pos(x1-1,y1-1),Pos1=d[r[pos1]];
        int pos2=pos(x2-1,y2-1),Pos2=d[r[pos2]];
        for(i=1,p1=d[pos1],p2=d[pos2];i<=xx;i++,p1=d[p1],p2=d[p2])swap(r[p1],r[p2]);
        for(i=1,p1=r[pos1],p2=r[pos2];i<=yy;i++,p1=r[p1],p2=r[p2])swap(d[p1],d[p2]);
        pos1=Pos1;pos2=Pos2;
        for(i=1;i<yy;i++)pos1=r[pos1];
        for(i=1;i<yy;i++)pos2=r[pos2];
        for(i=0,p1=pos1,p2=pos2;i<xx;i++,p1=d[p1],p2=d[p2])swap(r[p1],r[p2]);
        pos1=Pos1;pos2=Pos2;
        for(i=1;i<xx;i++)pos1=d[pos1];
        for(i=1;i<xx;i++)pos2=d[pos2];
        for(i=0,p1=pos1,p2=pos2;i<yy;i++,p1=r[p1],p2=r[p2])swap(d[p1],d[p2]);
    }
    for(i=1,p1=d[0];i<=n;i++,p1=d[p1])
    {
        for(j=1,p2=r[p1];j<=m;j++,p2=r[p2])
        {
            for(k=sum[p2-1]+1;k<=sum[p2];k++)
            printf("%c",ch[k]);
            printf(" ");
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2017-08-21 19:10  kakakakakaka  阅读(265)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效