[SDOI2010]粟粟的书架

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2010]粟粟的书架相关的知识,希望对你有一定的参考价值。

[SDOI2010]粟粟的书架

题意:

一个R * C的矩阵,每个位置都有个数page[ij],现在选定一个小矩阵范围(给左上角坐标,和右下角坐标),问这个范围内的数总和是否大于h,如果大于h的话最少选几个数aij
对于50%的数据,满足R, C≤200,M≤200,000;
另有50%的数据,满足R=1,C≤500,000,M≤20,000;
对于100%的数据,满足1≤Pi,j≤1,000,1≤Hi≤2,000,000,000。

题解:

题目数据给的很奇特,一半是R,C均小于200,另一半R=1(R=1也就是只有一行)
对于前一半数据,我们可以搞一个二位前缀和,二分最小值
value[i][j][k]表示从(1,1)到(i,j)的矩阵中数值>=k的数的总和
num[i][j][k]表示从(1,1)到(i,j)的矩阵中数值>=k的个数
value是为了计算区间总和是否大于h,num用于二分选择数的最小值
num和val的维护就是前缀和经典的容斥原理



if(page[i][j]>=k)value[i][j][k]=value[i-1][j][k]+value[i][j-1][k]-value[i-1][j-1][k]+page[i][j];
else value[i][j][k]=value[i-1][j][k]+value[i][j-1][k]-value[i-1][j-1][k]+0;

if(page[i][j]>=k)num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+1;
else num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+0;


对于后一半数据R=1,C<= 5 ∗ 1 0 5 5*10^5 5105,就不能用二位前缀和了,依旧是二分最小值,直接主席树就可以

代码:

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){
   ll s=0,w=1ll;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
void rd_test(){
	#ifdef ONLINE_JUDGE
	#else
		startTime = clock(); //计时开始
        freopen("in.txt","r",stdin);
	#endif
}
void Time_test(){
	#ifdef ONLINE_JUDGE
	#else
		endTime = clock(); //计时结束
   		printf("\\n运行时间为:%lfs\\n",(double)(endTime - startTime) / CLOCKS_PER_SEC);
	#endif
}
int r,c,m;
const int maxn=204;
ll val[maxn][maxn][1003];
int page[maxn][maxn];
int num[maxn][maxn][1004];
inline ll getval(int a,int b,int x,int y,int k){
	return val[x][y][k]-val[x][b-1][k]-val[a-1][y][k]+val[a-1][b-1][k];
}
inline ll getnum(int a,int b,int x,int y,int k){
	return num[x][y][k]-num[x][b-1][k]-num[a-1][y][k]+num[a-1][b-1][k]; 
}
void work2(){
	int maxx=0;
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			scanf("%d",&page[i][j]);
			maxx=max(maxx,page[i][j]);
		}
	}
	for(int k=0;k<=maxx;k++){
		for(int i=1;i<=r;i++){
			for(int j=1;j<=c;j++){
				if(page[i][j]>=k)val[i][j][k]=val[i-1][j][k]+val[i][j-1][k]-val[i-1][j-1][k]+page[i][j];
				else val[i][j][k]=val[i-1][j][k]+val[i][j-1][k]-val[i-1][j-1][k]+0;
				
				if(page[i][j]>=k)num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+1;
				else num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+0;
			}
		}
	}
	
	while(m--){
		int x1,y1,x2,y2;
		ll h;
		scanf("%d%d%d%d%lld",&x1,&y1,&x2,&y2,&h);
		ll ans=getval(x1,y1,x2,y2,0);
		if(ans<h)printf("Poor QLW\\n");
		else {

			int l=0,r=maxx+1;
			while(l+1<r){
				int mid=(l+r)>>1;
				if(getval(x1,y1,x2,y2,mid)>=h)l=mid;
				else r=mid;
			}
			int maxnum=getnum(x1,y1,x2,y2,l);
			printf("%d\\n",maxnum-((getval(x1,y1,x2,y2,l)-h)/l));
		}
	}
}
const int N=5500002;
int L[N],R[N],size[N],sum[N],rt[N],cnt;
inline void update(int &now,int pre,int l,int r,int x){
	now=++cnt;
	size[now]=size[pre]+1;
	sum[now]=sum[pre]+x;
	L[now]=L[pre];
	R[now]=R[pre];
	if(l==r)return ;
	int mid=l+r>>1;
	if(x<=mid)update(L[now],L[pre],l,mid,x);
	else update(R[now],R[pre],mid+1,r,x);
}
inline ll query(int Lrt,int Rrt,int l,int r,ll k){
	ll ans=0;
	while(l<r){
		int mid=(l+r)>>1;
		int Sum=sum[R[Rrt]]-sum[R[Lrt]];
		//优先取较大值,右侧 的数更大 
		if(Sum<k){
			ans+=size[R[Rrt]]-size[R[Lrt]];
			k-=Sum;
			r=mid;
			Rrt=L[Rrt];
			Lrt=L[Lrt]; 
		}
		else if(Sum>=k){
			l=mid+1;
			Rrt=R[Rrt];
			Lrt=R[Lrt]; 
		}
	}
	//debug("(k+l-1)/l",(k+l-1)/l);
	ans+=(k+l-1)/l;
	return ans; 
}
void work1(){
	int x;
	rt[0]=0;
	for(int i=1;i<=c;i++){
		scanf("%d",&x);
		update(rt[i],rt[i-1],1,1000,x);
	}
	while(m--){
		int x1,y1,x2,y2;
		ll h;
		scanf("%d%d%d%d%lld",&x1,&y1,&x2,&y2,&h);
		if(sum[rt[y2]]-sum[rt[y1-1]]<h){
			printf("Poor QLW\\n");
			continue;
		}
		printf("%d\\n",query(rt[y1-1],rt[y2],1,1000,h));
	} 
}
int main()
{
	rd_test();
	cin>>r>>c>>m;
	if(r==1)work1();
	else work2();
	//Time_test();
	return 0;
}




以上是关于[SDOI2010]粟粟的书架的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1926: [Sdoi2010]粟粟的书架

[Sdoi2010]粟粟的书架

BZOJ1926SDOI2010粟粟的书架 [主席树]

[SDOI2010]粟粟的书架 [主席树]

AC日记——[Sdoi2010]粟粟的书架 bzoj 1926

[SDOI2010]粟粟的书架