题解 P10061 [SNOI2024] 矩阵
VP 的时候想出来了,很开心!但是考试结束后 57 min 才过
该算法复杂度劣但常数小,当前最优解似乎也是该算法,现有题解未证明其复杂度,这里补一个。
发现旋转操作互相影响难以处理,尝试树形数据结构未果,发现操作间的互相影响并不太多,而且部分分中有
把询问分成大小为
代码较长,细节多。
#include<bits/stdc++.h>
using namespace std;
const int N=3003,p0=998244353,p1=1000000007,BLK=70,Q=19890;
int n,q,tp,ans,A[N][N],B[N][N];
struct node{int x,y,l1,l2,a,b,d,t;}st[Q];
int add(int x,int y){return x+y>=p1?x+y-p1:x+y;}
void rebuild(){
for(int i=1;i<=tp;++i)
if(st[i].d==0)
for(int j=0;j<=st[i].l1;++j)
for(int k=0;k<=st[i].l2;++k)
B[st[i].a+j][st[i].b+k]=add(A[st[i].x+j][st[i].y+k],st[i].t);
else if(st[i].d==1)
for(int j=0;j<=st[i].l1;++j)
for(int k=0;k<=st[i].l2;++k)
B[st[i].a-k][st[i].b+j]=add(A[st[i].x+j][st[i].y+k],st[i].t);
else if(st[i].d==2)
for(int j=0;j<=st[i].l1;++j)
for(int k=0;k<=st[i].l2;++k)
B[st[i].a-j][st[i].b-k]=add(A[st[i].x+j][st[i].y+k],st[i].t);
else
for(int j=0;j<=st[i].l1;++j)
for(int k=0;k<=st[i].l2;++k)
B[st[i].a+k][st[i].b-j]=add(A[st[i].x+j][st[i].y+k],st[i].t);
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) A[i][j]=B[i][j];
st[tp=1]={1,1,n-1,n-1,1,1,0,0};
}
void split1(int x){
for(int i=tp;i;--i)
if(st[i].d==0){
if(st[i].a<=x&&x<st[i].a+st[i].l1){
st[++tp]=st[i],st[i].l1=x-st[i].a;
st[tp].l1-=x-st[i].a+1,st[tp].x+=x-st[i].a+1,st[tp].a=x+1;
}
}else if(st[i].d==1){
if(st[i].a-st[i].l2<=x&&x<st[i].a){
st[++tp]=st[i],st[i].l2=st[i].a-x-1;
st[tp].l2-=st[i].a-x,st[tp].y+=st[i].a-x,st[tp].a=x;
}
}else if(st[i].d==2){
if(st[i].a-st[i].l1<=x&&x<st[i].a){
st[++tp]=st[i],st[i].l1=st[i].a-x-1;
st[tp].l1-=st[i].a-x,st[tp].x+=st[i].a-x,st[tp].a=x;
}
}else{
if(st[i].a<=x&&x<st[i].a+st[i].l2){
st[++tp]=st[i],st[i].l2=x-st[i].a;
st[tp].l2-=x-st[i].a+1,st[tp].y+=x-st[i].a+1,st[tp].a=x+1;
}
}
}
void split2(int x){
for(int i=tp;i;--i)
if(st[i].d==0){
if(st[i].b<=x&&x<st[i].b+st[i].l2){
st[++tp]=st[i],st[i].l2=x-st[i].b;
st[tp].l2-=x-st[i].b+1,st[tp].y+=x-st[i].b+1,st[tp].b=x+1;
}
}else if(st[i].d==1){
if(st[i].b<=x&&x<st[i].b+st[i].l1){
st[++tp]=st[i],st[i].l1=x-st[i].b;
st[tp].l1-=x-st[i].b+1,st[tp].x+=x-st[i].b+1,st[tp].b=x+1;
}
}else if(st[i].d==2){
if(st[i].b-st[i].l2<=x&&x<st[i].b){
st[++tp]=st[i],st[i].l2=st[i].b-x-1;
st[tp].l2-=st[i].b-x,st[tp].y+=st[i].b-x,st[tp].b=x;
}
}else{
if(st[i].b-st[i].l1<=x&&x<st[i].b){
st[++tp]=st[i],st[i].l1=st[i].b-x-1;
st[tp].l1-=st[i].b-x,st[tp].x+=st[i].b-x,st[tp].b=x;
}
}
}
int a,b,c,d;
bool chk(int i){
if(st[i].d==0)
return a<=st[i].a&&st[i].a+st[i].l1<=c&&b<=st[i].b&&st[i].b+st[i].l2<=d;
if(st[i].d==1)
return a<=st[i].a-st[i].l2&&st[i].a<=c&&b<=st[i].b&&st[i].b+st[i].l1<=d;
if(st[i].d==2)
return a<=st[i].a-st[i].l1&&st[i].a<=c&&b<=st[i].b-st[i].l2&&st[i].b<=d;
if(st[i].d==3)
return a<=st[i].a&&st[i].a+st[i].l2<=c&&b<=st[i].b-st[i].l1&&st[i].b<=d;
return 0;
}
int main(){
scanf("%d%d",&n,&q),st[tp=1]={1,1,n-1,n-1,1,1,0,0};
for(int i=1;i<=n;++i)
for(int j=1,c=1;j<=n;++j)
A[i][j]=c=c*1ll*(i+1)%p0;
for(int _=1,op;_<=q;++_){
scanf("%d%d%d%d%d",&op,&a,&b,&c,&d);
split1(c),split1(a-1),split2(d),split2(b-1);
if(op==1){
op=c-a+1;
for(int i=tp,x,y;i;--i)
if(chk(i)){
st[i].d=(st[i].d+1)&3;
x=op-st[i].b+b,y=st[i].a-a+1;
st[i].a=a+x-1,st[i].b=b+y-1;
}
}else{
scanf("%d",&op);
for(int i=tp;i;--i)
if(chk(i))
st[i].t=add(st[i].t,op);
}
if(_==q||_%BLK==0) rebuild();
}
for(int i=1,s=1;i<=n;++i)
for(int j=1;j<=n;++j)
s=s*12345ll%p1,ans=(ans+A[i][j]*1ll*s)%p1;
return printf("%d",ans),0;
}