ccf12-5祭坛(80分)

来源:互联网 发布:各个国家的域名 编辑:程序博客网 时间:2024/04/30 03:35

过几天要考ccf了,提前刷刷题。

链接 http://115.28.138.223/view.page?gpid=T43 

想了好久,只弄出80分的做法,100分的做法没有找到。

主要思路:

先考虑一个比较简单的情况:

给定一条横线上的点(a,b0),(a,b1)...(a,bn),以及一条竖线上的点(a0,b),(a1,b)...(an,b),求两条线能组成的最多结界数。

很容易找出做法:

1)找出两条线的交点(a,b)

2)从交点向外的四个方向(上下左右)上最少的点的数量就是最多结界数。

可以看出上面的想法是正确的。(一种构造方法是,将四个方向上离(a,b)最近的四个点连起来成为一个屏障,第二近的组成一个屏障,第三近的。。。)

这个可以通过二分查找确定出来。


知道了以上的简单情况,复杂的情况就好说了。。复杂的情况就是很多根竖线和很多根横线相交的问题。直观的想法就是,每根横线和每个竖线都测一下可以做多少结界。然后找出最大的并计数即可。但是这样有一点浪费时间,举个例子,如果我们得到的最大结界数是n,那么任何有少于2n-1的横线是没有必要再检查了(产生n个结界至少要有2n个点)。所以每当得到一个更大的结界数,我们就可以做一次更新,把那些不可能的线段剔除掉,这样可以节约一点时间。代码如下:


#include <iostream>#include <queue>#include <vector>#include <algorithm>#include <cstdio>using namespace std;struct point{int x,y;};bool comparebyx(const point& a,const point& b){return a.x<b.x ||(a.x==b.x && a.y<b.y);}bool comparebyy(const point& a,const point& b){return a.y<b.y ||(a.y==b.y && a.x<b.x);}bool compare(const vector<point>& a,const std::vector<point> b){return a.size()>b.size();}int findX(const vector<point>& sameY,int x){if(x<=sameY[0].x)return 0;int l = 0,r = sameY.size();while(l<r-1){int mid = (l+r)/2;if(sameY[mid].x==x){return 0;}elseif(sameY[mid].x<x)l = mid;elser = mid;}return min(l+1,int(sameY.size()-l-1));}int findY(const vector<point>& sameX,int y){if(y<=sameX[0].y)return 0;int l = 0,r = sameX.size();while(l<r-1){int mid = (l+r)/2;if(sameX[mid].y==y){return 0;}elseif(sameX[mid].y<y)l = mid;elser = mid;}return min(l+1,int(sameX.size()-l-1));}int main(){int  n,q,a,b;cin >> n>>q;vector<point> myVec(n);for(int i(0);i<n;i++){scanf("%d %d",&(myVec[i].x),&(myVec[i].y));}vector<point> myVec0(myVec);sort(myVec.begin(),myVec.end(),comparebyx);sort(myVec0.begin(),myVec0.end(),comparebyy);vector<vector<point> >sameX(1);vector<vector<point> >sameY(1);int index = 0;sameX[index].push_back(myVec[0]);for(int i(1);i<myVec.size();i++){if(myVec[i].x==myVec[i-1].x)sameX[index].push_back(myVec[i]);else{if(sameX[index].size()==1){sameX[index][0]=myVec[i];}else{sameX.push_back(vector<point>());index++;sameX[index].push_back(myVec[i]);}}}index = 0;sameY[index].push_back(myVec0[0]);for(int i(1);i<myVec0.size();i++){if(myVec0[i].y==myVec0[i-1].y)sameY[index].push_back(myVec0[i]);else{if(sameY[index].size()==1){sameY[index][0]=myVec0[i];}else{sameY.push_back(vector<point>());index++;sameY[index].push_back(myVec0[i]);}}}bool f = 1;sort(sameX.begin(),sameX.end(),compare);sort(sameY.begin(),sameY.end(),compare);int maxnum = 0,count = 0;/*for(int i(0);i<sameX.size();i++){for(int j(0);j<sameX[i].size();j++)cout << sameX[i][j].x<<' ';cout <<endl;}*/for(int i(0);i<sameX.size();i++){for(int j(0);j<sameY.size();j++){int x =sameX[i][0].x;int y = sameY[j][0].y;int res = min(findX(sameY[j],x),findY(sameX[i],y));if(res>maxnum){maxnum = res;count = 1;while(!sameX.empty() && sameX.back().size()<=2*maxnum-1)sameX.pop_back();while(!sameY.empty() && sameY.back().size()<=2*maxnum-1)sameY.pop_back();}elseif(res == maxnum)count++;}}if(q==1)cout << maxnum<<endl;elsecout << count<<endl;return 0;}/*26 20 51 11 51 93 53 104 04 14 24 44 64 94 115 05 25 45 85 95 105 116 57 58 59 1010 210 5*/
除了上面的想法,感觉还可以优化,优化的方面就是更新的时候其实可以剔除掉更多:对于剩下的横线,如果没有比自身纵坐标更大/更小的点,那么该横线就可以剔除掉。

0 0