x定义域 [0,x1]
推论一方格内从任一点出发的直线都是由从原点出发的直线平移形成的
y = kx
y = kx+b
推论二斜率<0的直线都与斜率大于零的直线对称
我们首先看一下从原点出发斜率小于1的直线公式
y = -kx
这里直线是在y轴的另一边因此我们要对直线做平移
y = -k(x+x1)
从而得出count(k<0)=count(k>0)
这里我们的思路基本形成
sumcount = count(k<0)+count(k>0)+count(k=0)+count(k=num/0)
= 2*count(k>0)+count(k=0)+count(k=num/0)
接下来 k=0是平行于x轴的直线不存在则是平行于y轴的直线
因此平行某个轴条数应该为定义域右闭区间减左闭区间+1
比如count(k==0) = x1-0+1;
因此这里未知量只剩下count(k>0)
这里的话其实我们就可以进行一个dfs
对于原点到点(i,j)的这条直线我们先做深搜将这条线的所有点置零
因为由于y=kx+b 是由y=kx或者 y = k(x-b)+c在x轴方向或是y轴方向平移得来的
所以我们只基于原点,遍历出所有的直线
因此如果顶点 i,j 被搜索过显然这类线已经计算过直接跳过
那么接下来第二个步骤就是进行平移了这个也是一个dfs不过策略不太相同
对于点(i,j) 每次横坐标加i纵坐标加j就是这条线的下一个网格点
这样的话接下来我们就可以做平移了
之前我们是从点i,j开始的这里是因为我们是从原点出发
那如果我们从点x,y出发
实际上上式就变成了深搜点(x+i,y+j)从而确定这条直线
这样我们只需要根据x,y关系遍历所有点即可
那么接下来的最后一个问题就是遍历所有点得到的直线是否会重合
答案是肯定的,我们可以回想一下<x,y>这个序对是否唯一
当x==y是是k为一的线,反之则不唯一
因此这里我设计了一个hashnum计算方法来映射出所有的关系
由于本题最大值到20 而20<(1<<5)的因此
我对int类型变量做了一个二进制划分
低五位存储y高五位存储x
我们每次搜索只是对于某一类直线做搜索
因此只需要关心hashnum是否一致即可
每次搜索将所有点值置为hashnum(x,y)
因此整理一下本题
1.遍历所有点->得到set(k>0)这样一个斜率大于零的所有直线集合
2.对于为了让直线集合元素不重复,对于点i,j我们要通过<x,y>关系将这条过原点直线的所有点置零
for(x=0,y=0;x+i<X&&y+j<Y;x+=i,y+=j)
grid[x][y] = true;
通过上面两部我们就得到了没有重复元素的K》0的集合
3.接下来我们就要对过原点直线做平移
做平移其实就是遍历所有点将从原点出发变成了从点ij出发
然后将当前点所在直线的所有点置hashnum(x,y)
hashnum = (x<<5)+y
for(i<X)
fot(j<Y)
dfs(i,j,X,Y)
#include <bits/stdc++.h>
using namespace std;
bool grid[50][50];
stack<short> xi,yi;
int table[50][50];
int hashnum,X,Y;
bool dfs(int p,int q,int x,int y){
if((p+x>=X||q+y>=Y)||(table[p][q]==hashnum||table[p+x][q+y]==hashnum))
return false;
int i = p,j=q;
for(;i+x<X&&y+j<Y;){//向前做位移
i+=x,j+=y;
table[i][j] = hashnum;
}
return true;
}
int main()
{
long long k=0,sum = 0;
cin>>X>>Y;
short i,j,p,q;
for(i=1;i<X;i++){
for(j = 1;j<Y;j++){
if(grid[i][j])
continue;
hashnum = (i<<5)+j;
for(p=i,q=j;p<X&&q<Y;p+=i,q+=j)
grid[p][q] = true;
for(q=0;q<Y;q++){
for(p=0;p<X;p++){
if(dfs(p,q,i,j))
sum++;
}
}
}
}
sum = (sum<<1);
sum+=(X+Y);
cout<<sum<<endl;
return 0;
}