應該是本身作的第一道組合題了吧,不過由於我比較菜,因此只是二合一node
咱們看完題目應該就能抽象出問題的本質:在一個子矩形中至少選取多少個數才能使得它們的和大於等於某個給定值。git
樸素的想法:經典的二維前綴和+容斥問題,考慮求出如下兩個數組:數組
\(num_{i,j,k}\),表示以\((i,j)\)爲右下角且矩陣中\(\ge k\)的數的個數ide
\(sum_{i,j,k}\),表示以\((i,j)\)爲右下角且矩陣中\(\ge k\)的數的總和優化
對於50%的數據,知足R, C≤200,M≤200,000ui
因此咱們直接暴力三維循環是能夠直接求出來的當心空間不要開爆了spa
考慮對於每一次詢問,咱們都經過二分求出那個最小的\(k\),便可間接得出答案。code
而後考慮優化,抱歉我不會了,咱們再仔細看這道題的數據有一個很奇怪的地方:get
另有50%的數據,知足R=1,C≤500,000,M≤20,000;string
這不是一行數嗎,那麼就是序列上的問題了。
這個就很套路了,因爲沒有修改咱們發現上主席樹是一個十分明智的選擇。
主席樹維護每個權值區間內數的個數以及總和,不過若是再直接二分就可能會T掉了
因此咱們要在主席樹上二分,咱們每一次優先考慮右子樹,能拿確定先把右子樹給拿光。
因此就寫完了,碼量也不算很大吧。
CODE
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; const int R=205; int r,c,m,q,ans,p[R][R],mx,opt,x1,x2,y1,y2,s; bool flag; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } namespace Square_sum { const int H=1005; int sum[R][R][H],num[R][R][H],p[R][R],mx=0; inline void init(void) { register int i,j,k; for (i=1;i<=r;++i) for (j=1;j<=c;++j) read(p[i][j]),mx=p[i][j]>mx?p[i][j]:mx; for (k=1;k<=mx;++k) for (i=1;i<=r;++i) for (j=1;j<=c;++j) { sum[i][j][k]=sum[i][j-1][k]+sum[i-1][j][k]-sum[i-1][j-1][k]+(p[i][j]>=k?p[i][j]:0); num[i][j][k]=num[i][j-1][k]+num[i-1][j][k]-num[i-1][j-1][k]+(p[i][j]>=k); } } inline int get_sum(int x1,int y1,int x2,int y2,int k) { return sum[x2][y2][k]-sum[x1-1][y2][k]-sum[x2][y1-1][k]+sum[x1-1][y1-1][k]; } inline int get_num(int x1,int y1,int x2,int y2,int k) { return num[x2][y2][k]-num[x1-1][y2][k]-num[x2][y1-1][k]+num[x1-1][y1-1][k]; } inline void solve(void) { if (get_sum(x1,y1,x2,y2,1)<s) { puts("Poor QLW"); return; } int l=1,r=mx,mid,res; while (l<=r) { mid=l+r>>1; if (get_sum(x1,y1,x2,y2,mid)>=s) res=mid,l=mid+1; else r=mid-1; } write(get_num(x1,y1,x2,y2,res)-(get_sum(x1,y1,x2,y2,res)-s)/res); putchar('\n'); } }; namespace President_tree { const int N=500005,H=1000; struct President_tree { int ch[2],size,sum; }node[N*11]; int rt[N],tot; inline void build(int &now,int l,int r) { now=++tot; if (l==r) return; int mid=l+r>>1; build(node[now].ch[0],l,mid); build(node[now].ch[1],mid+1,r); } inline void insert(int lst,int &now,int l,int r,int x) { now=++tot; node[now]=node[lst]; ++node[now].size; node[now].sum+=x; if (l==r) return; int mid=l+r>>1; if (x<=mid) insert(node[lst].ch[0],node[now].ch[0],l,mid,x); else insert(node[lst].ch[1],node[now].ch[1],mid+1,r,x); } inline int query(int lst,int now,int l,int r,int s) { if (l==r) return (s+l-1)/l; int mid=l+r>>1,dlt=node[node[now].ch[1]].sum-node[node[lst].ch[1]].sum; if (dlt>=s) return query(node[lst].ch[1],node[now].ch[1],mid+1,r,s); else return query(node[lst].ch[0],node[now].ch[0],l,mid,s-dlt)+node[node[now].ch[1]].size-node[node[lst].ch[1]].size; } inline void init(void) { register int i; int x; build(rt[0],1,H); for (register int i=1;i<=c;++i) read(x),insert(rt[i-1],rt[i],1,H,x); } inline void solve(void) { if (node[rt[y2]].sum-node[rt[y1-1]].sum<s) { puts("Poor QLW"); return; } write(query(rt[y1-1],rt[y2],1,H,s)); putchar('\n'); } }; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; read(r); read(c); read(m); if (r^1) Square_sum::init(),opt=1; else President_tree::init(); while (m--) { read(x1); read(y1); read(x2); read(y2); read(s); if (opt) Square_sum::solve(); else President_tree::solve(); } return 0; }