过几天要考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;
}
else
if(sameY[mid].x<x)
l = mid;
else
r = 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;
}
else
if(sameX[mid].y<y)
l = mid;
else
r = 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();
}
else
if(res == maxnum)
count++;
}
}
if(q==1)
cout << maxnum<<endl;
else
cout << count<<endl;
return 0;
}
/*
26 2
0 5
1 1
1 5
1 9
3 5
3 10
4 0
4 1
4 2
4 4
4 6
4 9
4 11
5 0
5 2
5 4
5 8
5 9
5 10
5 11
6 5
7 5
8 5
9 10
10 2
10 5
*/
除了上面的想法,感觉还可以优化,优化的方面就是更新的时候其实可以剔除掉更多:对于剩下的横线,如果没有比自身纵坐标更大/更小的点,那么该横线就可以剔除掉。