遇到过两种螺旋折线的题目
No.1 蓝桥杯第九届省赛C++大学B组第七题
螺旋折线
如图p1.png所示的螺旋折线经过平面上所有整点恰好一次。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。例如dis(0, 1)=3, dis(-2, -1)=9
给出整点坐标(X, Y),你能计算出dis(X, Y)吗?
【输入格式】
X和Y对于40%的数据,-1000 <= X, Y <= 1000
对于70%的数据,-100000 <= X, Y <= 100000
对于100%的数据, -1000000000 <= X, Y <= 1000000000【输出格式】
输出dis(X, Y)
【样例输入】
0 1【样例输出】
3
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
思路:
这个题呢,我们可以找出规律来
我们先观察(3,3)这个点 d(3,3)=6+5+5+4+4+3+3+2+2+1+1;
这个数一看就很有规律嘛,我们再看d(3,-3)=6+6+5+5+4+4+3+3+2+2+1+1;
很显然 我们首先呢 找一下这个数列的通项公式 1*2+2*2+3*2+4*2+5*2+......+n*2
2,4,6,8,10....显然的等差数列 那么前n项的和就是 Sn= n*(n*2+2)/2
化简就是 = n*(n+1) 故
= n*(n-1)
得到了这个公式后呢 这个题就算完成了一半了
然后呢我们对平面上的区域做个简单的划分
网上有很多种划分方法,我这个是我看到这个题后自己写的一种,并不是最优秀的
四个象限 我们把它划分为8个区域(看起来很多 其实并不复杂
站在不同区域的角度 n是不一样的
对于区域1、8、4、5 n就是|x|*2(y可以变 x是不变的) 对于2、3、6、7来说,n就是|y|*2
虽然有八个区域 但是我们计算的时候 其实是四种情况
- 对于区域1和8的坐标 我们先算出它跑到x=y这条线是多远(比如点(3,1),它到(3,3)距离是2),然后再加上n+
- 对于区域2和3呢 我们先算出它距离x=-y这条线有多远,然后再加上
就好了
- 对于区域4和5呢 我们计算出它距离y=x+1这条线有多远 然后再加上 n-1+
- 对于区域6和7呢 我们计算出它距离y=-x这条线有多远 然后再加上
(区域6和7的n比其他三块区域的n小1)
注意 有的同学可能会觉得 这样划分 5区域会有问题
因为 5区域我们取|x|*2 为n 但是5区域有个拐弯 x轴坐标是变了的
其实没问题 注意 题目说了 输入的坐标值是整数!整数!所以,下图两个绿色线中间的区域是没有输入数据的,所以5区域其实到拐角(在x坐标未改变之前)就结束了,x坐标改变后就到了6区域了。
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
int x,y,d,n;
long long sum;
int main(){
scanf("%d%d",&x,&y);
if(x>=0&&y>=0){//第一象限
if(x>=y){//区域1
n=x*2;
d=x-y+n+n*(n-1);
}
else{//区域2
n=y*2;
d=y+x+n*(n-1);
}
}
else if(x<=0&&y>=0){//第二象限
x=-x;
if(x>y){//区域4
n=x*2;
d=x-1+y+ n-1 +(n-2)*(n-1);
}
else{//区域3
n=y*2;
d=y-x+n*(n-1);
}
}
else if(x<=0&&y<=0){//第三象限
x=-x;y=-y;
if(x>y){//区域5
n=x*2;
d=x-1-y+n-1+(n-2)*(n-1);
}
else{//区域6
n=y*2;
d=y+x+ n*(n+1);
}
}
else if(x>=0&&y<=0){//第四象限
y=-y;
if(x>=y){//区域8
n=x*2;
d=x+y+n+n*(n-1);
}
else{//区域7
n=y*2;
d=y-x+n*(n+1);
}
}
printf("%d\n",d);
return 0;
}
No.2
题解:
这个题会发现,一圈走下来的步数是和边长有关系的。
当时我的做法是一层一层往里面走,一次走一层,直到走不了一层了为止
也过了 不过不是最优秀的做法
最好的二分层数 这样的话log复杂度就能找到临界层
另外 从里往外走也可以,总的步数减去里面的剩下的就是走的步数, 思路是一样的 同样二分层数 找到临界层
贴一下我比赛时候的代码 (没二分)
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
ll x1,y1,n1,k1;
void s(ll x,ll y,ll n,ll k){
while(1){
if( (4*n-4)>k ){
x1=x;y1=y;
n1=n;k1=k;return ;
}
else{
k=k-(4*n-4);
x+=1;y+=1;
if(n<=3){
x1=x;y1=y;n1=n;k1=k; return;
}
n-=2;
}
}
}
ll n,k;
int main(){
scanf("%lld%lld",&n,&k);
if(k==0){printf("1 1\n");return 0;}
s(1,1,n,k);
if(k1==0){printf("%lld %lld\n",x1,y1);return 0;}
while(1){
if(k1>=n1-1){//right
k1-=(n1-1);
y1=y1+n1-1;
}
else{
y1=y1+k1;k1=0;
}
if(k1==0){printf("%lld %lld\n",x1,y1);return 0;}
if(k1>=n1-1){//down
k1-=(n1-1);
x1=x1+n1-1;
}
else{
x1=x1+k1;k1=0;
}
if(k1==0){printf("%lld %lld\n",x1,y1);return 0;}
if(k1>=n1-1){//left
k1-=(n1-1);
y1=y1-(n1-1);
}
else{
y1=y1-k1;k1=0;
}
if(k1==0){printf("%lld %lld\n",x1,y1);return 0;}
if(k1>n1-1){//up
k1-=(n1-1);
x1=x1-(n1-1);
}
else{
x1=x1-k1;k1=0;
}
if(k1==0){printf("%lld %lld\n",x1,y1);return 0;}
}
return 0;
}