POJ 3179 离散化+二维前缀和+枚举(二分?)
离散化和前缀和以前做过,但是不熟,所以借鉴的lyd的代码(不过好像他也没用二分查找,虽然书上这么写的)不过代码中有一些剪枝和为下一步预处理的的操作可能优化了时间,反正62ms过了。。。
附上代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<set> 5 #include<vector> 6 #define INF 1<<30 7 using namespace std; 8 vector<int> X,Y; 9 const int maxn=510; 10 //typedef point pair<int,int>; 11 int sum[maxn][maxn]; 12 vector<pair<int,int> >p; 13 int main(){ 14 int C,n,x,y; 15 int a,b; 16 scanf("%d%d",&C,&n); 17 for(int i=1;i<=n;i++){ 18 scanf("%d%d",&a,&b); 19 p.push_back(make_pair(a,b)); 20 X.push_back(a); 21 Y.push_back(b); 22 } 23 //排序 24 sort(p.begin(),p.end()); 25 sort(X.begin(),X.end()); 26 X.erase(unique(X.begin(),X.end()),X.end());//去重 27 sort(Y.begin(),Y.end()); 28 Y.erase(unique(X.begin(),X.end()),X.end()); 29 x=X.size(),y=Y.size(); 30 X.push_back(INF),Y.push_back(INF); 31 //求二维前缀和 32 //sum[i][j]是点X[i-1][j-1]的前缀和 33 int pos=0; 34 for(int i=1;i<=x;i++){ 35 for(int j=1;j<=y;j++){ 36 sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 37 while(pos<n&&p[pos].first==X[i-1]&&p[pos].second==Y[j-1]){//判断该点是否有草 38 sum[i][j]++; 39 pos++; 40 } 41 } 42 } 43 //查找 44 int ans=INF; 45 for(int i=0;i<x;i++){//枚举起点x坐标 46 int i1=i+1;//终点x坐标 47 int s=0;//边长 48 int j=0;//起点y坐标 49 int j1=1;//终点y坐标 50 int val=sum[i1][j1]-sum[i][j1]-sum[i1][j]+sum[i][j]; 51 while(1){ 52 while(val<C&&(i1<x||j1<y)){ 53 s=min(X[i1]-X[i],Y[j1]-Y[j]); 54 while(X[i1]-X[i]<=s)i1++;//因为sum[i][j]是坐标(x-1,y-1)的前缀和 55 while(Y[j1]-Y[j]<=s)j1++; 56 val=sum[i1][j1]-sum[i][j1]-sum[i1][j]+sum[i][j]; 57 } 58 if(val<C)break;//剪枝 59 ans=min(ans,s+1); 60 j++;//y坐标+1 61 if(j==y)break;//y坐标枚举到头了,退出循环 62 if(j1<=j){ 63 j1=j+1; 64 s=0; 65 } 66 else{ 67 s-=Y[j]-Y[j-1];//边长也相应的减少 68 } 69 while(X[i1-1]-X[i]>s) i1--;//为下一轮计算做准备 70 val=sum[i1][j1]-sum[i][j1]-sum[i1][j]+sum[i][j]; 71 } 72 } 73 printf("%d\n",ans); 74 }

浙公网安备 33010602011771号