CCJ
发现了一个山洞,其中可以表示为 n × n n \times n n×n 的网格。 ( 1 , 1 ) (1,1) (1,1) 为山洞入口, ( n , n ) (n,n) (n,n) 为山洞出口,对于洞穴 ( i , j ) (i,j) (i,j) 所藏有的宝藏数量为 ( n 2 ) a i , j (n^2)^{a_{i,j}} (n2)ai,j。
CCJ
从入口进入后,每次可以从洞穴 ( i , j ) (i,j) (i,j) 进入到 洞穴 ( i + 1 , j ) (i+1,j) (i+1,j) 或 ( i , j + 1 ) (i,j+1) (i,j+1),并收集路径上所有的宝藏,之后从出口离开山洞。
但 CCJ
触发了山洞的机关,山洞会将一个矩形区域封闭起来,让 CCJ
无法进入,CCJ
想问你在各种情况下所能获得的最大宝藏数量 a n s m o d 1 0 9 + 7 ans \mod 10^9+7 ansmod109+7。
第一行一个正整数 T ( 1 ≤ T ≤ 5 ) T(1\leq T \leq 5) T(1≤T≤5) 表示数据组数。
对于每组数据,第一行两个正整数 n n n 和 q q q,表示山洞大小和询问数量。
接下来的 n n n 行,第 i i i 行包含 n n n 个正整数 a i , 1 , a i , 2 , . . . , a i , n a_{i,1},a_{i,2},...,a_{i,n} ai,1,ai,2,...,ai,n,表示每个洞穴的宝藏数量。
接下来 q q q 行,每行四个正整数 x l , x r , y l , y r x_l,x_r,y_l,y_r xl,xr,yl,yr,封闭的洞穴 ( i , j ) (i,j) (i,j) 满足 x l ≤ i ≤ x r x_l \leq i \leq x_r xl≤i≤xr 且 y l ≤ j ≤ y r y_l \leq j \leq y_r yl≤j≤yr,数据保证存在从入口到出口的路径。
对于每组数据,输出 q q q 行,每行一个整数 a n s ans ans 为题目所求。
样例输入
1
2 2
2 3
1 4
1 1 2 2
2 2 1 1
样例输出
276
336
下发样例范围
下发数据点编号 | n n n | q q q | a i , j a_{i,j} ai,j |
---|---|---|---|
1 1 1 | ≤ 100 \leq100 ≤100 | ≤ 1 0 4 \leq10^4 ≤104 | ≤ 3 \leq3 ≤3 |
2 2 2 | ≤ 100 \leq100 ≤100 | ≤ 1 0 5 \leq10^5 ≤105 | ≤ n \leq n ≤n |
3 3 3 | ≤ 400 \leq400 ≤400 | ≤ 2 × 1 0 5 \leq2 \times 10^5 ≤2×105 | ≤ n 2 \leq n^2 ≤n2 |
测试点编号 | n n n | q q q | a i , j a_{i,j} ai,j |
---|---|---|---|
1 ∼ 3 1\sim3 1∼3 | ≤ 100 \leq100 ≤100 | ≤ 1 0 4 \leq10^4 ≤104 | ≤ 3 \leq3 ≤3 |
4 ∼ 7 4\sim7 4∼7 | ≤ 100 \leq100 ≤100 | ≤ 1 0 5 \leq10^5 ≤105 | ≤ n \leq n ≤n |
8 ∼ 10 8\sim10 8∼10 | ≤ 400 \leq400 ≤400 | ≤ 2 × 1 0 5 \leq2 \times 10^5 ≤2×105 | ≤ n 2 \leq n^2 ≤n2 |
时间限制为 std
的两倍。
2020 Multi-University Training Contests
#include<bits/stdc++.h>
#define N 170005
using namespace std;
const unsigned long long p=1331;
const int mod=1e9+7;
inline int read(){
int x=0;char s=getchar();
while(s<'0'||s>'9')s=getchar();
while(s>='0'&&s<='9'){
x=(x<<3)+(x<<1)+s-'0';s=getchar();}
return x;
}
inline int power(int x,int c){
int now=1;
while(c){
if(c&1)now=1LL*now*x%mod;
x=1LL*x*x%mod;c>>=1;
}
return now;
}
struct seg{
int ls=0,rs=0;
unsigned long long sum=0;
}t[7000005];
int tot,f[405][405],g[405][405];
int pf[405][405],pg[405][405],sf[405][405],sg[405][405];
int a[405][405],af[405][405],ag[405][405];
int pn[405][405],sn[405][405],fi[405][405],nsq;
unsigned long long pp[N];
inline int add(){
t[++tot].ls=0;t[tot].rs=0;t[tot].sum=0;
return tot;
}
inline void push(int p){
if(!p)return ;
if(!t[p].ls)t[p].ls=add();
if(!t[p].rs)t[p].rs=add();
}
int pd(int p1,int p2,int q1,int q2,int l,int r){
if(l==r){
return t[p1].sum+t[p2].sum<t[q1].sum+t[q2].sum;
}
int mid=(l+r)>>1;
push(p1);push(p2);push(q1);push(q2);
if(t[t[p1].rs].sum+t[t[p2].rs].sum!=t[t[q1].rs].sum+t[t[q2].rs].sum)return pd(t[p1].rs,t[p2].rs,t[q1].rs,t[q2].rs,mid+1,r);
else return pd(t[p1].ls,t[p2].ls,t[q1].ls,t[q2].ls,l,mid);
}
int change(int p,int q,int l,int r,int tl){
t[q]=t[p];
if(l==r){
t[q].sum++;
return q;
}
int mid=(l+r)>>1;
push(p);t[q]=t[p];
if(tl<=mid)t[q].ls=change(t[p].ls,add(),l,mid,tl);
else t[q].rs=change(t[p].rs,add(),mid+1,r,tl);
t[q].sum=t[t[q].ls].sum+t[t[q].rs].sum*pp[(mid-l+1)];
return q;
}
int main(){
// freopen("sample3.in","r",stdin);
// freopen("data.in","r",stdin);
// freopen("biao.out","w",stdout);
int T=read();
pp[0]=1;
for(int i=1;i<N;++i)pp[i]=pp[i-1]*p;
while(T--){
tot=-1;add();
int n=read(),q=read();nsq=n*n;
memset(f,0,sizeof(f));memset(g,0,sizeof(g));
memset(af,0,sizeof(af));memset(ag,0,sizeof(ag));
memset(sf,0,sizeof(sf));memset(pf,0,sizeof(pf));
memset(sg,0,sizeof(sg));memset(pg,0,sizeof(pg));
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)a[i][j]=read(),fi[i][j]=power(nsq,a[i][j]);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(pd(f[i-1][j],0,f[i][j-1],0,1,nsq))f[i][j]=change(f[i][j-1],add(),1,nsq,a[i][j]),af[i][j]=af[i][j-1];
else f[i][j]=change(f[i-1][j],add(),1,nsq,a[i][j]),af[i][j]=af[i-1][j];
af[i][j]=(af[i][j]+fi[i][j])%mod;
}
}
for(int i=n;i;--i){
for(int j=n;j;--j){
if(pd(g[i+1][j],0,g[i][j+1],0,1,nsq))g[i][j]=change(g[i][j+1],add(),1,nsq,a[i][j]),ag[i][j]=ag[i][j+1];
else g[i][j]=change(g[i+1][j],add(),1,nsq,a[i][j]),ag[i][j]=ag[i+1][j];
ag[i][j]=(ag[i][j]+fi[i][j])%mod;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(pd(g[i+1][j],0,g[i][j+1],0,1,nsq))g[i][j]=g[i][j+1];
else g[i][j]=g[i+1][j];
ag[i][j]=(ag[i][j]-fi[i][j])%mod;
}
}
for(int i=1;i<=n;++i){
pf[i][0]=0;pg[i][0]=0;
for(int j=1;j<=n;++j){
if(pd(pf[i][j-1],pg[i][j-1],f[i][j],g[i][j],1,nsq))pf[i][j]=f[i][j],pg[i][j]=g[i][j],pn[i][j]=(af[i][j]+ag[i][j])%mod;
else pf[i][j]=pf[i][j-1],pg[i][j]=pg[i][j-1],pn[i][j]=pn[i][j-1];
}
}
for(int i=n;i;--i){
sf[i][n+1]=0;sg[i][n+1]=0;
for(int j=n;j;--j){
if(pd(sf[i][j+1],sg[i][j+1],f[i][j],g[i][j],1,nsq))sf[i][j]=f[i][j],sg[i][j]=g[i][j],sn[i][j]=(af[i][j]+ag[i][j])%mod;
else sf[i][j]=sf[i][j+1],sg[i][j]=sg[i][j+1],sn[i][j]=sn[i][j+1];
}
}
int ans=0;
for(int i=1;i<=q;++i){
int lx=read(),rx=read(),ly=read(),ry=read();
int fl=pf[rx+1][ly-1],gl=pg[rx+1][ly-1],fr=sf[lx-1][ry+1],gr=sg[lx-1][ry+1];
if(rx+1>n||ly-1<1)ans=sn[lx-1][ry+1];
else{
if(lx-1<1||ry+1>n)ans=pn[rx+1][ly-1];
else{
if(pd(fl,gl,fr,gr,1,nsq))ans=sn[lx-1][ry+1];
else ans=pn[rx+1][ly-1];
}
}
printf("%d\n",(ans+mod)%mod);
}
}
return 0;
}
/*
1
4 1
3 1 2 3
3 1 2 3
2 3 2 3
2 2 1 1
1 3 4 4
*/