问题 A: 奇怪的道路

时间限制: 1 Sec 内存限制: 128 MB

[提交] [状态]

题目描述

从前,有一座网格城市,城市中每个房子占据一个正方形小格子的中心,每个正方形小格子的边长均为1。

这座城市道路的设计方式是这样的,首先,定义(a)图为一个基本图形,其阶为1,之后,将(a)图中每一个房子都用一个基本图形代替,得到(b)图,那么(b)图的阶即为2,再将(b)图中的每一个房子都用基本图形替代,得到阶为3的©图,以此类推,只要知道这座城市的阶n,就可以知道它的道路设计。

奇怪的道路(递归回溯)_数据

这种七拐八弯的道路设计使得这座城市之间的道路交通运输相当不便,于是该市的市长决定改造一下这座城市的道路,但在此之前他需要做一系列的评估,比如这座网格城市中,连接第i1行第j1列的房屋与第i2行第j2列的房屋之间(两座房屋可能相同)的道路有多长,由于这种道路设计太过奇怪,人力难以计算,于是这个任务就交给作为软件工程师的你了。
输入
每个测试点第一行有两个正整数n,T,表示城市的阶数和询问数。
接下来T行,每行4个正整数i1,j1,i2,j2,表示要查询的两个房屋的坐标。
输出
对每个询问输出一行相应的值表示答案。
样例输入 Copy
2 4
2 1 3 1
3 2 2 2
2 3 3 3
3 4 2 4
样例输出 Copy
13
11
1
3
提示
样例解释:
样例对应题目中的(b)图。
第一个询问问的是图中编号为2的房子与编号为15的房子的距离。
第二个询问问的是图中编号为14的房子与编号为3的房子的距离。
第三个询问问的是图中编号为8的房子与编号为9的房子的距离。
第四个询问问的是图中编号为10的房子与编号为7的房子的距离。

对于100%的数据,均有1≤n≤15,1≤i1,j1,i2,j2≤2n,1≤T≤10000。

思路: 回溯递归分治
从上图中我们可以找到一定规律,他分四块 ,为左上,左下,右上,右下。我们可以看出在整体上,这四个是 从左上到右上,再到右上 再到右下再到左下,也就是个顺时针,然后减一层就是单看一个分区,

  • 左上 他相当于上层的规律 发生对角线对称的规律,
  • 右上 它与上层 规律一样。+ 这层的平方
  • 左下 他是关于反对角线对称,+2倍的这层的平方
  • 右下 他与上层 归路也一样,+3倍的这层的平方
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define
const int mod=998244353;
const int MOD=10007;

inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}

priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小
map<ll,ll>mp;

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
ll qpow(ll a,ll b){
ll sum=1;
while(b){
if(b&1) sum=sum*a;
b>>=1;
a=a*a;
}
return sum;
}

ll dfs(ll n,ll x,ll y){//分象限递归
if(n==0) return 1;
ll mid=qpow(2,n-1);
ll sum1=mid*mid;
if(x<=mid&&y<=mid){
return dfs(n-1,y,x);
}else if(x<=mid&&y>mid)
return sum1+dfs(n-1,x,y-mid);
else if(x>mid&&y>mid) return 2*sum1+dfs(n-1,x-mid,y-mid);
else return 3*sum1+dfs(n-1,mid+1-y,2*mid+1-x);
}

int main(){
cin>>n>>m;
for(int i=1;i<=m;i++) {
ll x,y;
cin>>x>>y>>l>>r;
cout<<abs(dfs(n,l,r)-dfs(n,x,y))<<endl;
}
return 0;
}


2020蓝桥杯国赛:

有个类似的题只不过是3*3的还没补。