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;
}