DTOJ#4955. CCJ的探险

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(1T5) 表示数据组数。

对于每组数据,第一行两个正整数 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 xlixr y l ≤ j ≤ y r y_l \leq j \leq y_r yljyr,数据保证存在从入口到出口的路径。

对于每组数据,输出 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 13 ≤ 100 \leq100 100 ≤ 1 0 4 \leq10^4 104 ≤ 3 \leq3 3
4 ∼ 7 4\sim7 47 ≤ 100 \leq100 100 ≤ 1 0 5 \leq10^5 105 ≤ n \leq n n
8 ∼ 10 8\sim10 810 ≤ 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

*/
这个错误是因为`multiprocessing`模块在进行进程间通信时,需要将数据进行序列化(pickle)和反序列化操作。然而,某些对象(如`select.epoll`对象)是不能被序列化的,因此会引发`TypeError: can't pickle select.epoll objects`错误。 要解决这个问题,一种方法是避免将不可序列化的对象传递给进程间通信的机制(如`Queue`、`Pipe`等)。如果你确实需要使用这些对象,可以考虑使用`multiprocessing.Manager`提供的共享内存对象来进行进程间通信。 下面是一个示例代码,展示了如何使用`multiprocessing.Manager`来共享一个`select.epoll`对象: ```python import multiprocessing def process_function(epoll): # 在这里使用epoll对象 # ... if __name__ == '__main__': manager = multiprocessing.Manager() epoll = manager.epoll() # 创建进程 process = multiprocessing.Process(target=process_function, args=(epoll,)) process.start() process.join() ``` 在上述示例代码中,我们首先导入`multiprocessing.Manager`类。然后,通过调用`manager.epoll()`方法创建一个可以在多个进程中共享的`epoll`对象。接下来,我们可以将这个共享的`epoll`对象传递给进程函数进行使用。 需要注意的是,在使用`multiprocessing.Manager`创建的共享对象中,所有的数据和操作都是通过进程间通信来进行的,因此会有一定的性能开销。因此,只有在必要时才使用共享对象,并确保将其封装在进程函数中,以避免频繁的数据传递和通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值