121. 赶牛入圈 AcWing
作者:互联网
错误思路:
参考了激光炸弹,用变量存储三叶草的最大坐标,枚举左下角时只枚举到最大坐标处,结合二分求最小边长,但我的二分完全写错了,我写的二分是如果Mid不是最小的边长,则返回False,但实际上二分的check函数是检查答案的合理性(即这个mid边长下,是否存在正方形至少含C面积三叶草)
纠正思路:
xy坐标的范围在1~10000,而实际上只有500个要用,因此可以想到离散化,并且这道题答案显然具有单调性,二分法是必定的.这道题离散化坐标实际上是压缩了矩阵,将没有三叶草的地方都删去,但是这样二分距离就不是简单地枚举i+mid,j+mid.
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 10010; 4 int sum[N][N],n,c; 5 typedef pair<int,int> pii; 6 pii p[N]; 7 vector<int> alls; 8 /* 9 一.二分答案:二分边长,如果面积内>=c,则为合格解(二分,首先找合格解) 10 二.N范围是10000,暴力枚举正方形的某个点一定超时, 但是实际的n<500,可以考虑离散化 11 */ 12 int Get_id(int x) 13 { 14 return lower_bound(alls.begin(),alls.end(),x)-alls.begin(); 15 } 16 bool check(int mid){ 17 for(int i=1,x=0;i<alls.size();i++){ 18 while(alls[i]-alls[x+1]+1>mid) x++; 19 for(int j=1,y=0;j<alls.size();j++){ 20 while(alls[j]-alls[y+1]+1>mid) y++; 21 int s = sum[i][j]-sum[i][y]-sum[x][j]+sum[x][y]; 22 if(s>=c) return true; 23 } 24 } 25 return false; 26 } 27 int main() 28 { 29 scanf("%d%d",&c,&n); 30 alls.push_back(0); 31 for(int i=1;i<=n;i++) { 32 scanf("%d%d",&p[i].first,&p[i].second); 33 alls.push_back(p[i].first); alls.push_back(p[i].second); 34 } 35 sort(alls.begin(),alls.end()); 36 alls.erase(unique(alls.begin(),alls.end()),alls.end()); 37 for(int i=1;i<=n;i++) { 38 sum[Get_id(p[i].first)][Get_id(p[i].second)]++; 39 //printf("%d %d\n",Get_id(p[i].first),Get_id(p[i].second)); 40 } 41 for(int i=1;i<alls.size();i++) 42 for(int j=1;j<alls.size();j++) 43 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 44 int low = 1; int high = 1e4; 45 while(low<high){ 46 int mid = low+high>>1; 47 if(check(mid)) high = mid; 48 else low = mid+1; 49 } 50 printf("%d\n",low); 51 }
注意:
我们计算的前缀和是经过压缩的前缀和,i与j的距离不是1而是要带入alls的下标才能计算,这样check出的mid才是真正的距离,如果我们采用以下方案计算:
1 bool check(int mid){//这样返回的是压缩后的mid的边长 2 for(int i=1;i<alls.size();i++){//y总的做法返回的就是压缩前的边长 3 //while(alls[i]-alls[x+1]+1>mid) x++;//移动到最后一个与(i,j)距离>mid的点 4 int x = Get_id(alls[i]+mid-1); 5 for(int j=1;j<alls.size();j++){ 6 while(alls[j]-alls[y+1]+1>mid) y++;???为什么 7 int y = Get_id(alls[j]+mid-1);//压缩前实际要+3,压缩后只要+1 8 // printf("%d %d\n",x,y); 9 int s = sum[x][y]-sum[i-1][y]-sum[x][j-1]+sum[i-1][j-1]; 10 if(s>=c) return true; 11 } 12 } 13 return false; 14 }错误思路
x返回的是alls[i]加上多少后,才能得到与(i,j)形成符合条件的正方形的数字,例如alls[i]=1,如果形成符合条件的正方形最少加上2,因为lower_bound返回>=的数字,这样就会导致答案错误,正解就是枚举坐标,看哪个下标会与(i,j)相差mid且符合条件(上面的正确代码基本默写y总的思路),如果代入alls内没有的数字就会产生偏差
标签:二分,入圈,int,sum,mid,121,枚举,alls,赶牛 来源: https://www.cnblogs.com/ndfwblog/p/14169586.html