首页 > 其他分享 >P10061 [SNOI2024] 矩阵

P10061 [SNOI2024] 矩阵

时间:2024-01-22 19:13:22浏览次数:34  
标签:元素 int xa 矩阵 long 旋转 P10061 && SNOI2024

原题链接

考虑记录每个元素相邻的四个元素,发现每次旋转只会影响最周围一圈的点与旁边一圈点的连接,所以考虑十字链表维护,单次操作 \(O(n)\) 可以接受。

矩阵加怎么做,我们还是采用上述的思路,在维护元素相邻的时候维护相邻两个元素的差值,这样可以 \(O(n)\) 矩阵加,因为还是只对最周围一圈操作。查询元素值是单次 \(O(n)\) 的,因为你要从链表最边缘开始走,但是查询 \(n\) 个连续的元素值是均摊 \(O(1)\) 的。

然后思考一下细节,发现每次旋转以后方向是会变的,要知道每次应该往哪个方向走应当知道当前元素旋转了几次,每次旋转都是对一个子矩阵,所以还是相当于矩阵加,多维护一个即可。总结是:

  • \(O(n)\) 求出最周围一圈与旁边一圈的元素值和旋转次数。
  • \(O(n)\) 将最周围一圈点的旋转次数都加一。
  • \(O(n)\) 修改十字链表,更新链表值,元素值差值和旋转次数差值。

但是代码很难写,值得一提的细节是在旋转时可以先存下来最周围一圈每个点和其相邻点还有两者的方向,这样应该要好写一点。还有就是将旋转次数加一时要不重不漏,需要注意角落和只有一条线或点的情况。

卡常的话,最开始不要快速幂,直接用 \((i,j-1)\) 的值乘 \(i+1\)。操作中不需要取模,只开几个 long long 比较快。大量的 %4 可以改成 &3,但这条可能有副作用。

我的代码没有封装,因为我觉得封装了更难调。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=3010;
int MOD=998244353,n,q;long long ans;
struct node{long long num,v[4];int sum,a[4],s[4];}p[MAXN*MAXN];
struct rota{int x,tx,y,ty;}K[4][MAXN];
inline int N(int x,int y)
{
    if(x>n||y>n) return 0;
    return x*(n+1)+y;
}
signed main()
{
    // freopen("matrix.in","r",stdin);
    // freopen("matrix.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n>>q;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        {
            int cur=N(i,j);
            p[cur].num=(j==1)?(i+1):p[cur-1].num*(i+1)%MOD;
            p[cur].a[0]=N(i,j+1);
            p[cur].a[1]=N(i+1,j);
            p[cur].a[2]=N(i,j-1);
            p[cur].a[3]=N(i-1,j);
        }
    for(int i=1;i<=n;++i) p[i].a[1]=N(1,i);
    for(int i=1;i<=n;++i) p[i*(n+1)].a[0]=N(i,1);
    for(int i=0;i<(n+1)*(n+1);++i)
        for(int j=0;j<4;++j)
            p[i].v[j]=p[p[i].a[j]].num-p[i].num;
    while(q--)
    {
        int opt,xa,ya,xb,yb,d;long long S=0;
        cin>>opt>>xa>>ya>>xb>>yb;
        if(opt==1)
        {
            S=0;
            for(int i=0,cur=xa*(n+1),c=0;i<=yb;++i)
            {
                int nxt=p[cur].a[c];
                if(i>=ya&&i<=yb)
                {
                    p[cur].num=S;p[cur].sum=c;
                    int x=cur,tx=(c+3)%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx]+1)%4;
                    p[y].num=S+p[x].v[tx],p[y].sum=(c+p[x].s[tx])%4;
                    K[0][i-ya]={x,tx,y,ty};
                }
                S=S+p[cur].v[c];
                c+=p[cur].s[c];c=(c+4)%4;cur=nxt;
            }
            S=0;
            for(int i=0,cur=xb*(n+1),c=0;i<=yb;++i)
            {
                int nxt=p[cur].a[c];
                if(i>=ya&&i<=yb)
                {
                    p[cur].num=S;p[cur].sum=c;
                    int x=cur,tx=(c+1)%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx]+3)%4;
                    p[y].num=S+p[x].v[tx],p[y].sum=(c+p[x].s[tx])%4;
                    K[1][i-ya]={x,tx,y,ty};
                }
                S=S+p[cur].v[c];
                c+=p[cur].s[c];c=(c+4)%4;cur=nxt;
            }
            S=0;
            for(int i=0,cur=ya,c=0;i<=xb;++i)
            {
                int nxt=p[cur].a[(c+1)%4];
                if(i>=xa&&i<=xb)
                {
                    p[cur].num=S;p[cur].sum=c;
                    int x=cur,tx=(c+2)%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx])%4;
                    p[y].num=S+p[x].v[tx],p[y].sum=(c+p[x].s[tx])%4;
                    K[2][i-xa]={x,tx,y,ty};
                }
                S=S+p[cur].v[(c+1)%4];
                c+=p[cur].s[(c+1)%4];c=(c+4)%4;cur=nxt;
            }
            S=0;
            for(int i=0,cur=yb,c=0;i<=xb;++i)
            {
                int nxt=p[cur].a[(c+1)%4];
                if(i>=xa&&i<=xb)
                {
                    p[cur].num=S;p[cur].sum=c;
                    int x=cur,tx=c%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx]+2)%4;
                    p[y].num=S+p[x].v[tx],p[y].sum=(c+p[x].s[tx])%4;
                    K[3][i-xa]={x,tx,y,ty};
                }
                S=S+p[cur].v[(c+1)%4];
                c+=p[cur].s[(c+1)%4];c=(c+4)%4;cur=nxt;
            }  
            for(int i=0;i<=xb-xa;++i) p[K[0][i].x].sum++;
            if(xa!=xb) for(int i=0;i<=xb-xa;++i) p[K[1][i].x].sum++;
            for(int i=1;i<xb-xa;++i) p[K[2][i].x].sum++;
            if(ya!=yb) for(int i=1;i<xb-xa;++i) p[K[3][i].x].sum++;
            for(int i=0;i<=xb-xa;++i)
            {
                int x=K[0][i].x,tx=K[0][i].tx;
                int y=K[2][xb-xa-i].y,ty=K[2][xb-xa-i].ty;
                p[x].a[tx]=y,p[y].a[ty]=x;
                p[x].v[tx]=p[y].num-p[x].num;
                p[y].v[ty]=p[x].num-p[y].num;
                p[x].s[tx]=(p[y].sum-p[x].sum+4)%4;
                p[y].s[ty]=(p[x].sum-p[y].sum+4)%4;
            }
            for(int i=0;i<=xb-xa;++i)
            {
                int x=K[1][i].x,tx=K[1][i].tx;
                int y=K[3][xb-xa-i].y,ty=K[3][xb-xa-i].ty;
                p[x].a[tx]=y,p[y].a[ty]=x;
                p[x].v[tx]=p[y].num-p[x].num;
                p[y].v[ty]=p[x].num-p[y].num;
                p[x].s[tx]=(p[y].sum-p[x].sum+4)%4;
                p[y].s[ty]=(p[x].sum-p[y].sum+4)%4;
            }
            for(int i=0;i<=xb-xa;++i)
            {
                int x=K[2][i].x,tx=K[2][i].tx;
                int y=K[1][i].y,ty=K[1][i].ty;
                p[x].a[tx]=y,p[y].a[ty]=x;
                p[x].v[tx]=p[y].num-p[x].num;
                p[y].v[ty]=p[x].num-p[y].num;
                p[x].s[tx]=(p[y].sum-p[x].sum+4)%4;
                p[y].s[ty]=(p[x].sum-p[y].sum+4)%4;
            }
            for(int i=0;i<=xb-xa;++i)
            {
                int x=K[3][i].x,tx=K[3][i].tx;
                int y=K[0][i].y,ty=K[0][i].ty;
                p[x].a[tx]=y,p[y].a[ty]=x;
                p[x].v[tx]=p[y].num-p[x].num;
                p[y].v[ty]=p[x].num-p[y].num;
                p[x].s[tx]=(p[y].sum-p[x].sum+4)%4;
                p[y].s[ty]=(p[x].sum-p[y].sum+4)%4;
            }
        }
        if(opt==2)
        {
            cin>>d;
            for(int i=0,cur=xa*(n+1),c=0;i<=yb;++i)
            {
                if(i>=ya&&i<=yb)
                {
                    int x=cur,tx=(c+3)%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx]+1)%4;
                    p[x].v[tx]-=d,p[y].v[ty]+=d;
                }
                int nxt=p[cur].a[c];c+=p[cur].s[c];c=(c+4)%4;cur=nxt;
            }
            for(int i=0,cur=xb*(n+1),c=0;i<=yb;++i)
            {
                if(i>=ya&&i<=yb)
                {
                    int x=cur,tx=(c+1)%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx]+3)%4;
                    p[x].v[tx]-=d,p[y].v[ty]+=d;
                }
                int nxt=p[cur].a[c];c+=p[cur].s[c];c=(c+4)%4;cur=nxt;
            }
            for(int i=0,cur=ya,c=0;i<=xb;++i)
            {
                if(i>=xa&&i<=xb)
                {
                    int x=cur,tx=(c+2)%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx])%4;
                    p[x].v[tx]-=d,p[y].v[ty]+=d;
                }
                int nxt=p[cur].a[(c+1)%4];c+=p[cur].s[(c+1)%4];c=(c+4)%4;cur=nxt;
            }
            for(int i=0,cur=yb,c=0;i<=xb;++i)
            {
                if(i>=xa&&i<=xb)
                {
                    int x=cur,tx=c%4;
                    int y=p[x].a[tx],ty=(c+p[x].s[tx]+2)%4;
                    p[x].v[tx]-=d,p[y].v[ty]+=d;
                }
                int nxt=p[cur].a[(c+1)%4];c+=p[cur].s[(c+1)%4];c=(c+4)%4;cur=nxt;
            }
        }
    }
    MOD=1e9+7;long long P=1;
    for(int i=1;i<=n;++i)
    {
        long long S=0;
        for(int j=i*(n+1),c=0;j;)
        {
            if(j%(n+1)) P=P*12345%MOD,ans=(ans+P*S)%MOD;
            int nxt=p[j].a[c];S=(S+p[j].v[c])%MOD;
            c+=p[j].s[c];c=(c+4)%4;j=nxt;
        }
    }
    cout<<(ans+MOD)%MOD<<'\n';return 0;
}

标签:元素,int,xa,矩阵,long,旋转,P10061,&&,SNOI2024
From: https://www.cnblogs.com/int-R/p/17980764/P10061

相关文章

  • P10060 [SNOI2024] 树 V 图
    原题链接首先想到\(f\)值相同的点一定构成一个连通块,所以应当有\(k\)个连通块并且每个连通块\(f\)值互不相同。判断一下\([1,k]\)是否在\(f\)中都出现过,并且是否有\(k-1\)条边两个端点的\(f\)值不同,若有不符合的就是非法输入,直接输出\(0\)。考虑\(k=2\)的部分......
  • 微前端(矩阵项目)代码将单个文件合并到指定分支
    确保你当前位于要合并文件的源分支上。可以使用gitbranch命令查看当前分支,并使用gitcheckout命令切换到源分支。使用gitcheckout命令切换到目标分支,即你想要合并文件的分支。gitcheckoutsource_branch--path/to/filesource_branch是包含要合并文件的源分支,path/to/f......
  • 最大子矩阵和
    给定一个大矩阵,矩阵一般由$0$或$1$组成,要求你求出由$0$或$1$组成的最大子矩阵做法颇多,先介绍一种做法,后续的单调栈,动态规划以及二维前缀和+二分再补充 P4147玉蟾宫-洛谷|计算机科学教育新生态(luogu.com.cn)把每个格子向上延伸的连续空格看成一条悬线,并用......
  • 矩阵代数的 Burnside 定理
    我们详细重述并证明[1,Sec.1.2]中的Burnside定理及其相关推论.下面设V是复数域C上的有限维线性空间,B(V)是V上的线性变换代数;I是B(V)的单位元.Burnside定理证明较长.为使逻辑顺畅,先做一些准备工作.Lemma1设A是B(V)上的乘法半群,若A不可约,则对任意非零的x......
  • stm32笔记[13]-矩阵键盘
    摘要在蓝桥杯物联网的CT127C开发板上测试矩阵键盘模块;复用矩阵键盘的io口和i2c3的io口;在屏幕显示按下的按键.开发环境Keil5.35.00HAL库版本:STM32CubeFW_L0V1.12.0STM32CubeMX:6.2.1原理简介stm32的引脚复用voidHAL_I2C_MspDeInit(I2C_HandleTypeDef*i2cHandle)......
  • OpenCV仿射变换+投射变换+单应性矩阵
    OpenCV仿射变换+投射变换+单应性矩阵本来想用单应性求解小规模运动的物体的位移,但是后来发现即使是很微小的位移也会带来超级大的误差甚至错误求解,看起来这个方法各种行不通,还是要匹配知道深度了以后才能从三维仿射变换来入手了,纠结~estimateRigidTransform():计算多个二维......
  • 基于矩阵分解的协同过滤算法
    引言随着互联网、大数据等新技术的迅速发展,人们的生活变得更加便捷,但同时也导致网络数据爆炸式增长。为了快速帮助用户找到感兴趣的内容,越来越多的研究者致力于推荐算法的研究,以提高推荐质量,向用户推荐更符合其喜好的内容。然而,目前的推荐算法仍存在数据稀疏性、隐私保护和冷启动......
  • [国家集训队] 矩阵乘法 整体二分
    [国家集训队]矩阵乘法题目描述给你一个\(n\timesn\)的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第\(k\)小数。输入格式第一行有两个整数,分别表示矩阵大小\(n\)和询问组数\(q\)。第\(2\)到第\((n+1)\)行,每行\(n\)个整数,表示这个矩阵。第\((i+1)\)行......
  • 矩阵
    这道题目就是一个二维hash模板讲一下二维哈希二维的数据结构一般都是先对一个既定的行做列(一维)上的操作,然后再把若干列当成一维处理行(数组指针指向一个二维数组就可以这么理解)设\(hash[i][j]\)表示前\(i\)行前\(j\)列的矩阵的hash值我们先对列做hash(设进制数为\(base_1\))for(......
  • hdu 4990 Reading comprehension(矩阵乘法)
    Readtheprogrambelowcarefullythenanswerthequestion.pragmacomment(linker,"/STACK:1024000000,1024000000")includeincludeincludeincludeincludeincludeconstintMAX=100000*2;constintINF=1e9;intmain(){intn,m,ans,i;while(sc......