[NOIP模拟][链表]裁剪表格

本文介绍了一道NOIP模拟题,涉及矩阵和链表操作。题目要求在给定的矩阵中,通过交换大小相同的子矩阵,求最终矩阵。题目难点在于如何高效地实现矩阵交换,解决方案是利用链表记录矩阵边界,时间复杂度为O(n*q)。文章提供了四种不同的代码实现,包括暴力解法和不同方式的链表解法。
摘要由CSDN通过智能技术生成

题目描述:
题目大意:
给一个n*m的矩阵,每个格子都有一个数字v,每次交换两个大小相同的不重叠的子矩阵,输出最后的矩阵。
输入格式:
第一行三个整数n,m,q代表表格的行数和列数和操作次数;
接下来n行,每行m个整数,表示格中的数字。
接下来q行,每行六个数字, r1,c1,r2,c2,h,w ,分别表示第一个矩形左上角所在行、所在列,第二个矩形左上角所在行、所在列,这两个矩形的高度和宽度(保证着两个矩形都在原有表格内)。
输出格式:
输出n行,每行m个整数,表示最后的矩阵。
样例输入:

4 4 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
1 1 3 3 2 2
3 1 1 3 2 2

样例输出:

4 4 3 3
4 4 3 3
2 2 1 1
2 2 1 1
数据范围:
对于10%的数据,所有的v=1;
对于30%的数据,n,m≤300,q≤300;
对于60%的数据,n,m≤1000,q≤500;
对于100%的数据,2≤n,m≤1000,1≤q≤500;1≤v≤1000000。

题目分析:
先吐槽一下这道题,因为题面中提到高级数据结构,然后有许多人写了splay,出题人为了卡那些人,后面的数据的询问就专门针对splay,结果导致暴力踩标算,直接拿满(暴力就是指直接模拟交换)。后来后面数据改了一下还是有80分,加register还是可以满分。(主要是数据很难兼顾同时卡暴力和splay)。
分析:这道题其实是一道链表题,我们可以记录四个方向(上下左右),每次交换,其实只用修改两个矩形的四周那一圈的连接。于是时间复杂度O(n*q)。
具体操作:先从起点(初始为(1,1),如果(1,1)与其它点交换,则这个点就成为了起点(因为实际上它被换到了(1,1)的位置))出发,分别走到这两个矩形的左上角,然后绕矩形走一圈(在两个矩形上的点是对应着一起走),每次交换两个矩形对应点连出去的指向和外面被连接的点所连回来的指向。这样就相当于交换整个矩形。
还可以优化:只记录两个指向,右、下,因为你输出只根据向右和向下就可以输出,而向右和向下就可以表示4个方向(上面的情况是在双向修改,这里就是单向的)。
链表可以一般写法,也可以指针写。
下附4份代码:1、暴力,2、我写的记录四个方向的链表,3、标算的记录两个方向的链表,4、记录两个方向的链表的指针写法。
附代码:
1、暴力+register:
是我考试代码直接加的register,所以还有特判部分

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;

const int N=1e3+100;
int n,m,q,a[N][N];
bool check;

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

int main()
{
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);

    n=readint();m=readint();q=readint();
    for(register int i=1;i<=n;i++)
        for(register int j=1;j<=m;j++)
        {
            a[i][j]=readint();
            if(a[i][j]!=1) check=true;
        }
    if(check==false)
    {
        <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值