P2468 [SDOI2010] 粟粟的书架

P2468 [SDOI2010] 粟粟的书架

题意简述:

给你一个矩阵,每次给定一个矩形和一个值 h ,让你在这个矩形中选 k 个数使得这 k 个数的和 h 且最小化这个 k

对于 50% 的数据,满足 R,C200M2×105

另有 50% 的数据,满足 R1C5×105M2×104

对于 100% 的数据,满足 1Pi,j10001Hi2×109

Solution:

看到这个猎奇的数据范围我们就知道这题肯定不简单,首先我们来看一下后50分怎么拿:

不难想到我们可以建一颗可持久化权值线段树,然后在主席树上查询在 [rtl1+rt[r]] 的答案,具体实现就是权值线段树上尽量往右子树跳,kt[x].val 就全部取。

然后再来说一下前50分怎么拿,注意到:  

满足 1Pi,j1000R,C200

我们可以开一个sum[R][C][inf] 一个二维前缀和sumi,j,k来存
(1,1)(i,j) 这个矩形内权值等于 k 的数量

然后对于每个查询,直接暴力从 1000>1 扫一遍然后统计答案就好了

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,q;
struct Solve1
{
#define N 500005
#define inf 2000000000
//Segment_Tree
struct Segment_Tree{
int rt[N],cnt=0;
struct Tree{
int ls,rs,val,cnt;
}t[N*40];
void insert(int &x,int y,int l,int r,int k)
{
t[x=++cnt] = t[y];
t[x].val+=k;t[x].cnt++;
if(l==r)return;
int mid=l+r>>1;
if(k<=mid)insert(t[x].ls,t[y].ls,l,mid,k);
if(mid<k)insert(t[x].rs,t[y].rs,mid+1,r,k);
}
void query(int x,int y,int l,int r,int L,int R,int &k,int &cnt)
{
if(k<=0)return ;
int Val=-t[x].val+t[y].val,Cnt=-t[x].cnt+t[y].cnt;
if(L<=l&&r<=R&&k>=Val)
{
k-=Val;
cnt+=Cnt;
return;
}
if(l==r)
{
int val=Val/Cnt;
cnt+=(k/val);
k-=(k/val)*val;
if(k){cnt++;k-=val;}
return;
}
int mid=l+r>>1;
if(mid<R)query(t[x].rs,t[y].rs,mid+1,r,L,R,k,cnt);
if(L<=mid) query(t[x].ls,t[y].ls,l,mid,L,R,k,cnt);
}
}T;
void work()
{
for(int i=1,x;i<=m;i++)
{
scanf("%d",&x);
T.insert(T.rt[i],T.rt[i-1],1,inf,x);
}
for(int i=1;i<=q;i++)
{
int l,r,x,y,k;
scanf("%d%d%d%d%d",&x,&l,&y,&r,&k);
int ans=0;
if(-T.t[T.rt[l-1]].val+T.t[T.rt[r]].val<k){printf("Poor QLW\n");continue;}
T.query(T.rt[l-1],T.rt[r],1,inf,1,inf,k,ans);
printf("%d\n",ans);
}
}
#undef N
#undef inf
}S_1;
struct Solve_2{
#define N 205
#define inf 1005
int sum[N][N][inf],a[N][N];
void work()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
sum[i][j][a[i][j]]++;
}
}
for(int i=2;i<=n;i++)for(int k=1;k<=1000;k++)sum[i][1][k]+=sum[i-1][1][k];
for(int j=2;j<=m;j++)for(int k=1;k<=1000;k++)sum[1][j][k]+=sum[1][j-1][k];
for(int i=2;i<=n;i++)for(int j=2;j<=m;j++)for(int k=1;k<=1000;k++)
{
sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+sum[i][j][k];
}
for(int i=1;i<=q;i++)
{
int x_0,y_0,x_1,y_1,h,ans=0;
scanf("%d%d%d%d%d",&x_0,&y_0,&x_1,&y_1,&h);
for(int k=1000;k;k--)
{
int cnt=sum[x_1][y_1][k]-sum[x_1][y_0-1][k]-sum[x_0-1][y_1][k]+sum[x_0-1][y_0-1][k];
if(h>(k*cnt))
{
ans+=cnt;
h-=(k*cnt);
}
else
{
ans+=(h/k);
h-=((h/k)*k);
while(h>0)
{
ans++;
h-=k;
}
break;
}
}
if(h>0)printf("Poor QLW\n");
else printf("%d\n",ans);
}
}
#undef N
#undef inf
}S_2;
int main()
{
//freopen("P2468.in","r",stdin);freopen("P2468.out","w",stdout);
cin>>n>>m>>q;
if(n==1)S_1.work();
else S_2.work();
return 0;
}
posted @   liuboom  阅读(0)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示