一开始没看清题,以为不一定平行。。。然后就不会了。。。
看了题解写了一遍,发现求某个值最好写在一个函数里,否则有时候代码中间要出一个特例就会很麻烦,甚至要goto。写在函数里一个return就ok了。
然后枚举矩形时最好不要重边,否则一行点就会算两次。重边的情况特判输出就好了。
看了大白书上的代码又模仿了一遍,发现模仿别人写代码很难学到什么东西。因为你会想当然的凭着记忆去写代码,从而导致事实上你根本就没有深入理解这段代码的含义,如果AC了,你也就是抄了一遍而已,如果WA了,你自己从头到尾查一遍,就会发现有一些很低级的逻辑错误,而且还不太容易找到。这都是因为你想当然的觉得对导致的。但是看别人代码还是能学到东西的,一直闷着自己写,代码风格和习惯可能会一直很糟糕。看了别人的代码后,就会灵机一动,然后学到一些优秀的代码技巧和实现方法,就会发现自己的代码有多么啰嗦。
然后是思路。
其实分析下也能大概知道O(n^4)的算法在一秒内只能跑n=100的数据。
然而有多组数据,所以是一定要优化的。
部分枚举是跑不了了,但问题是枚举哪些部分。预处理,记录和维护那些数据。
正常都会想到枚举2~3条边,然后算出答案。
大白书上用的是枚举3条边,然后O(1)算出最大值。
其实能少枚举一维就是很大的优化了,也需要很多信息维护的。
枚举上下边界,然后从左到右枚举右边界,维护最优的左边界,O(1)算出答案。
答案是“算”出来的,而且一定由两部分组成,一部分是只跟右边界有关的量,另一部分是只跟左边界有关的量,然后只跟左边界有关的量就维护成最优值。至于跟上下边界有关的量就暂时当成常量,可以预处理一下。
很容易想到某种题就是给一个数列,求最大子串和,要预处理一个sum数组,sum[i]表示前i个数的和。sum[i]-sum[j-1]就是[j,i]的和。
这题也一样,预处理一个sum数组,sum[k]就代表横坐标小于等于第k条竖边的在上下边界上的点的个数。sum[i]-sum[j-1]就是在j和i边之间的在上下边界上的点的个数。然后再加上左右边界上不再上下边界上的点的个数就是答案。sum[i]-sum[j-1]+on[i]+on[j],把i,j分开那就是sum[i]+on[i]+on[j]-sum[j-1]我们就要维护关于j的最优值,即on[j]-sum[j-1]的最大值。显然从左到右扫一遍极易维护。
我的代码跟大白书上的方法一样,但是跟上面说的略有不同,但大同小异。
我的代码
#include<bits/stdc++.h>
#define maxn 110
#define INF 0X3F3F3F3F
using namespace std;
struct star
{
int x,y;
bool operator < (const star& rhs) const
{
if(x!=rhs.x) return x<rhs.x;
else return y<rhs.y;
}
}S[maxn];
int N;
int kase;
int Y[maxn];
int l;
int lft[maxn],on[maxn],on2[maxn];
int main()
{
while(scanf("%d",&N)==1&&N)
{
for(int i=1;i<=N;i++)
{
scanf("%d %d",&S[i].x,&S[i].y);
Y[i]=S[i].y;
}
sort(S+1,S+1+N);
sort(Y+1,Y+1+N);
l=unique(Y+1,Y+1+N)-Y;
if(l<=3)
{
printf("Case %d: %d\n",++kase,N);
continue;
}
int ANS=-INF;
for(int i=1;i<l;i++)
for(int j=1;j<i;j++)
{
int cnt=0;
int k=0;
int sum=0;
int shang=0;
int zhong=0;
while(k!=N)
{
shang=0;
zhong=0;
do
{
k++;
if(S[k].y==Y[i]||S[k].y==Y[j]) shang++;
else if(S[k].y>Y[j]&&S[k].y<Y[i]) zhong++;
}while(k+1<=N&&S[k+1].x==S[k].x);
lft[k]=sum;
on[k]=zhong;
on2[k]=zhong+shang;
sum+=shang;
cnt++;
}
if(cnt<=2)
{
printf("Case %d: %d\n",++kase,N);
goto here;
}
int MAX=-INF;
int PRE=-INF;
k=0;
cnt=0;
while(k!=N)
{
do
{
k++;
}while(k+1<=N&&S[k+1].x==S[k].x);
MAX=max(MAX,PRE+lft[k]+on2[k]);
PRE=max(PRE,on[k]-lft[k]);
}
ANS=max(ANS,MAX);
}
printf("Case %d: %d\n",++kase,ANS);
here:;
}
return 0;
}
模仿大白书
#include<bits/stdc++.h>
#define maxn 110
#define INF 0X3F3F3F3F
using namespace std;
struct star
{
int x,y;
bool operator < (const star& rhs) const
{
if(x!=rhs.x) return x<rhs.x;
else return y<rhs.y;
}
}S[maxn];
int N;
int lft[maxn],on[maxn],on2[maxn];
int Y[maxn];
int solve()
{
sort(S,S+N);
sort(Y,Y+N);
int l=unique(Y,Y+N)-Y;
if(l<=2) return N;
int ANS=-INF;
for(int i=0;i<l;i++)
for(int j=0;j<i;j++)
{
int k=0;
for(int u=0;u<N;u++)
{
if(u==0||S[u-1].x!=S[u].x)
{
k++;
on[k]=on2[k]=0;
lft[k]=lft[k-1]+on2[k-1]-on[k-1];
}
if(S[u].y>Y[j]&&S[u].y<Y[i]) on[k]++;
if(S[u].y>=Y[j]&&S[u].y<=Y[i]) on2[k]++;
}
if(k<=2) return N;
int PRE=-INF;
for(int u=1;u<=k;u++)
{
ANS=max(ANS,PRE+lft[u]+on2[u]);
PRE=max(PRE,on[u]-lft[u]);
}
}
return ANS;
}
int kase;
int main()
{
while(scanf("%d",&N)==1&&N)
{
for(int i=0;i<N;i++)
{
scanf("%d %d",&S[i].x,&S[i].y);
Y[i]=S[i].y;
}
printf("Case %d: %d\n",++kase,solve());
}
return 0;
}