Stupid cat & doge
典型的分治
找遍了所有搜索引擎居然没有此题的题解
那我发一个好了
如何分治
此题考虑当前等级和上一等级的关系
例如 右上的部分和右下的部分和上一部分一样
而左上和左下是顺时针旋转和逆时针旋转
根据此关系来推导出坐标的变换即可
注释很详细不多解释
#include <cmath>
#include <iostream>
#define LL long long int
using namespace std;
int base_x[5]={0,1,1,2,2};//第一等级为基底
int base_y[5]={0,1,2,2,1};//任何等级都由第一等级推过去
long long int k,a,b,t;
LL search_y(LL k,LL n);//声明函数
double dis(LL x1,LL y1,LL x2,LL y2){return sqrt(pow(x1-x2,2)+pow(y1-y2,2))*10;}
//计算距离函数
LL search_x(LL k,LL n)
{
if(k==1)return base_x[n];//边界 如果是第一等级 直接返回答案 即该标号横坐标
else{
LL map=pow(2,k<<1);//地图的大小 即k等级的动物园共有几个房屋
int block=(n%(map>>2)==0)?(n/(map>>2)):(n/(map>>2))+1;
//计算标号为n的房屋在地图的哪一个方位(左上右上左下右下)特殊条件特殊判断
if(block==1)return search_y(k-1,n);//分类搜索答案
//如果是第一块 旋转后横坐标变成纵坐标
else if(block==2)return search_x(k-1,(n%(map>>2)==0)?n/2:n%(map>>2));
//如果是第二块 形状和上一等级一样无需变化 只是求出上一等级的横坐标即可
else if(block==3)return search_x(k-1,n%(map>>1))+pow(2,k-1);
//如果是第三块 形状也一样 求出上一等级横坐标还要加上半个边长
else if(block==4)return pow(2,k)+1-search_y(k-1,n%(map*3/4));
//如果是第四块 逆时针旋转 先顺时针旋转再中心对称
}
}
/*注释同上*/
LL search_y(LL k,LL n)
{
if(k==1)return base_y[n];
else{
LL map=pow(2,k<<1);
int block=(n%(map>>2)==0)?(n/(map>>2)):(n/(map>>2))+1;
if(block==1)return search_x(k-1,n);
else if(block==2)return search_y(k-1,(n%(map>>2)==0)?n/2:n%(map>>2))+pow(2,k-1);
else if(block==3)return search_y(k-1,n%(map>>1))+pow(2,k-1);
else if(block==4)return pow(2,k-1)+1-search_x(k-1,n%(map*3/4));
}
}
/*注释同上*/
int main()
{
cin>>t;//数据总量
while(t--){
cin>>k>>a>>b;//读入等级数 StupidCat和Doge的房屋编号
LL x1=search_x(k,a);//求出Cat的房屋横坐标
LL y1=search_y(k,a);//求出Cat的房屋纵坐标
LL x2=search_x(k,b);//求出Doge的房屋横坐标
LL y2=search_y(k,b);//求出Doge的房屋纵坐标
double ans=dis(x1,y1,x2,y2);//计算两者之间的距离
LL temp=ans;//以下是四舍五入计算
cout<<((ans>=temp+0.5)?(temp+1):temp)<<endl;
}
}
End。