P1255 数楼梯
题目本质是 Fibonacci 数列
走楼梯,要么一次走一格,要么一次走两格
那每次的走法 = 上一格的方案数 + 上上格的方案数
这就有了递推公式:
a[i] = a[i - 1] + a[i - 2]
这题要注意数据,开 long long 也只能得60points :
#include<iostream>
using namespace std;
long long a[10000];
int main(){
int n;
cin >> n;
a[1] = 1; a[2] = 2;
for (int i = 3; i <= n; i++)
a[i] = a[i - 1] + a[i - 2];
cout << a[n];
return 0;
}
所以需要用高精度算法,注意 n=1 || n=2 时候的特殊判断 :
#include<iostream>
using namespace std;
int a[5000], b[5000], c[5000];
void jiafa(int a[], int b[]) {
int jw = 0;
for (int i = 0; i < 5000; i++) {
c[i] = (a[i] + b[i] + jw) % 10;
jw = (a[i] + b[i] + jw) / 10;
}
}
int main(){
int n;
cin >> n;
if (n == 2 || n == 1) {
cout << n;
}
else {
a[0] = 1; b[0] = 2;
for (int i = 3; i <= n; i++) {
jiafa(a, b);
for (int i = 0; i < 5000; i++)
a[i] = b[i], b[i] = c[i];
}
int i = 4999;
for (i; i >= 0; i--) {
if (c[i] != 0)
break;
}
for (i; i >= 0; i--)
cout << c[i];
}
return 0;
}
P1002 [NOIP2002 普及组] 过河卒
卒要么向下走要么向右走
那么每次的走法 = 左一格的方案数 + 上一格的方案数
这就有了递推公式:
a[i][j] = a[i - 1][j] + a[i][j - 1]
首先由于数据比较大开数组时选择long long( 十年OI一场空,不开浪浪见祖宗 )
紧接着初始化二维数组:有马的地方都不可以过去,因此都初始为0,如下图 ( 以样例为例 )
初始化时要注意如果第0行或者第0列有马时 (或者马可以跳到这种位置) 的特殊情况,如下图:
此时第0行或者第0列都应该开始变为0
接着就利用递推公式开始完善二维数组,注意有马的地方不需要赋值,如下图 ( 以样例为例 )
#include<iostream>
using namespace std;
long long a[26][26];
int main(){
a[0][0] = 0;
for (int i = 1; i < 25; i++)
a[0][i] = 1, a[i][0] = 1;
int bx, by, cx, cy;
cin >> bx >> by >> cx >> cy;
if (cx >= 0 && cy >= 0)a[cx][cy] = 0;
if (cx + 2 >= 0 && cy + 1 >= 0)a[cx + 2][cy + 1] = 0;
if (cx + 1 >= 0 && cy + 2 >= 0)a[cx + 1][cy + 2] = 0;
if (cx - 1 >= 0 && cy + 2 >= 0)a[cx - 1][cy + 2] = 0;
if (cx - 2 >= 0 && cy + 1 >= 0)a[cx - 2][cy + 1] = 0;
if (cx - 2 >= 0 && cy - 1 >= 0)a[cx - 2][cy - 1] = 0;
if (cx - 1 >= 0 && cy - 2 >= 0)a[cx - 1][cy - 2] = 0;
if (cx + 1 >= 0 && cy - 2 >= 0)a[cx + 1][cy - 2] = 0;
if (cx + 2 >= 0 && cy - 1 >= 0)a[cx + 2][cy - 1] = 0;
int x = 1;
while (a[x][0] == 1)
x++;
for (x; x < 25; x++)
a[x][0] = 0;
int y = 1;
while (a[0][y] == 1)
y++;
for (y; y < 25; y++)
a[0][y] = 0;
for (int i = 1; i < 25; i++) {
for (int j = 1; j < 25; j++) {
if ((i == cx && j == cy) || (i == cx + 2 && j == cy + 1) || (i == cx + 1 && j == cy + 2) || (i == cx - 1 && j == cy + 2) || (i == cx - 2 && j == cy + 1) || (i == cx - 2 && j == cy - 1) || (i == cx - 1 && j == cy - 2) || (i == cx + 1 && j == cy - 2) || (i == cx + 2 && j == cy - 1))
continue;
else
a[i][j] = a[i - 1][j] + a[i][j - 1];
}
}
cout << a[bx][by];
return 0;
}
P1044 [NOIP2003 普及组] 栈
这题本质是 Catalan数,可直接用数论方法来 AC ,当然也可以递推:
创建二维数组 a [ i ] [ j ] 表示此时(栈内有 i 个数,未进栈的有 j 个数)有多少种情况
由于栈内数字要么出栈pop:则栈内元素减一,a [ i - 1 ] [ j ]
要么压栈push:则栈内元素加一,未进栈元素减一,a [ i + 1 ] [ j - 1 ]
而当栈内没有元素时:则只能进栈,a [ i + 1 ] [ j - 1 ]
这就有了递推公式:
a[i][j] = a[i - 1][j] + a[i + 1][j - 1]
a[i][j] = a[i + 1][j - 1]
首先初始化二维数组:当 a [ i ] [ 0 ] 时,i 个元素全部进栈,故只有一种情况,即a [ i ] [ 0 ] = 1
如下图:
紧接着初始化二维数组:注意根据递推公式要一列一列的赋值,如下图:
最后输出 a [ 0 ] [ n ] 即可
#include<iostream>
using namespace std;
int a[20][20];
int main(){
int n; cin >> n;
for (int i = 1; i < 20; i++)
a[i][0] = 1;
for (int j = 1; j < 20; j++) {
for (int i = 0; i < 20; i++) {
if (i == 0)
a[i][j] = a[i + 1][j - 1];
else
a[i][j] = a[i - 1][j] + a[i + 1][j - 1];
}
}
cout << a[0][n];
return 0;
}
P1028 [NOIP2001 普及组] 数的计算
通过简单的枚举,可以发现递推规律:a [ i ] =1 + a[ 1 ] + a[ 2 ] +...+ a[ i/2 ]
此题数据较小,开 int 也是可以过的,保险起见还是开浪浪:
#include<iostream>
using namespace std;
long long a[1001];
int main(){
int n; cin >> n;
a[1] = 1, a[2] = 2, a[3] = 2;
if (n >= 4) {
for (int i = 4; i <= 1000; i++) {
long long ans = 1;
int x = i / 2;
for (int j = 1; j <= x; j++) {
ans += a[j];
}
a[i] = ans;
}
cout << a[n];
}
else
cout << a[n];
return 0;
}
P1464 Function
乍一看题目,纯纯递归嘛,直接上代码:
#include<iostream>
using namespace std;
long long w(long long a, long long b, long long c) {
if (a <= 0 || b <= 0 || c <= 0)
return 1;
if (a > 20 || b > 20 || c > 20)
return w(20, 20, 20);
if (a < b && b < c)
return w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c);
else
return w(a - 1, b, c) + w(a - 1, b - 1, c) + w(a - 1, b, c - 1) - w(a - 1, b - 1, c - 1);
}
int main(){
long long a, b, c;
while (scanf("%lld %lld %lld", &a, &b, &c)) {
if (a == -1 && b == -1 && c == -1)
break;
printf("w(%lld, %lld, %lld) = ", a, b, c);
printf("%lld\n", w(a, b, c));
}
return 0;
}
好的,喜提 0point:数据都能过,但是全部超时,(ˉ▽ˉ;)...,
因此必须使用记忆化搜索:每次计算后用一个数组来记录答案,这样下一次计算时就直接调用数组内存好的答案就行了,避免了不必要的重复计算,大大节省时间
#include<iostream>
using namespace std;
long long fun[50][50][50];
int w(long long a, long long b, long long c) {
if (a <= 0 || b <= 0 || c <= 0)
return 1;
if (a > 20 || b > 20 || c > 20)
return w(20, 20, 20);
if (fun[a][b][c] != 0)
return fun[a][b][c];
if (a < b && b < c)
return fun[a][b][c] = w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c);
else
return fun[a][b][c] = w(a - 1, b, c) + w(a - 1, b - 1, c) + w(a - 1, b, c - 1) - w(a - 1, b - 1, c - 1);
}
int main(){
long long a, b, c;
while (scanf("%lld %lld %lld", &a, &b, &c)) {
if (a == -1 && b == -1 && c == -1)
break;
printf("w(%lld, %lld, %lld) = ", a, b, c);
printf("%lld\n", w(a, b, c));
}
return 0;
}
P2437 蜜蜂路线
题目本质是 Fibonacci 数列,与数楼梯一样,开浪浪只能得 40points:
#include<iostream>
using namespace std;
long long a[1001];
int main(){
int m, n; cin >> m >> n;
int x = n - m + 1;
a[1] = 0, a[2] = 1, a[3] = 2;
for (int i = 4; i <= 1000; i++) {
a[i] = a[i - 1] + a[i - 2];
}
cout << a[x];
return 0;
}
因此使用高精度加法算法:
#include<iostream>
using namespace std;
int a[300], b[300], c[300];
void jiafa(int a[], int b[]) {
int jw = 0;
for (int i = 0; i < 300; i++) {
c[i] = (a[i] + b[i] + jw) % 10;
jw = (a[i] + b[i] + jw) / 10;
}
}
int main(){
int m, n; cin >> m >> n;
int x = n - m + 1;
a[0] = 1, b[0] = 1;
for (int i = 3; i <= x; i++) {
jiafa(a, b);
for (int i = 0; i < 300; i++)
a[i] = b[i], b[i] = c[i];
}
int i = 299;
for (i; i >= 0; i--)
if (c[i] != 0)
break;
for (i; i >= 0; i--)
cout << c[i];
return 0;
}
P1164 小A点菜
创建二维数组 b [ i ] [ j ] 表示此时( i 个菜,花 j 元)有多少种情况
动态规划:当钱和价格相等时 b [ i ][ j ] = b[ i - 1][ j ] + 1
当钱大于价格时 b [ i ][ j ] = b[ i - 1][ j ] + b[ i - 1][ j - a[ i ] ]
当钱小于价格时 b [ i ][ j ] = b[ i - 1][ j ]
#include<iostream>
using namespace std;
int a[101];
int b[101][10001];
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (j == a[i])
b[i][j] = b[i - 1][j] + 1;
if (j > a[i])
b[i][j] = b[i - 1][j] + b[i - 1][j - a[i]];
if (j < a[i])
b[i][j] = b[i - 1][j];
}
}
cout << b[n][m];
return 0;
}
P1036 [NOIP2002 普及组] 选数
#include<iostream>
using namespace std;
int n, k;
int a[25];
long long ans;
//判断素数函数
int ispirme(int x) {
for (int i = 2; i * i < x; i++) {
if (x % i == 0)
return 0;
}
return 1;
}
//深度搜索 dfs ( 开始选数,已经选好数字的个数,选好所有数的和 )
void dfs(int start, int cnt, int sum) {
int i;
//如果选中的个数刚好满足,直接判断是否为素数
if (cnt == k && ispirme(sum))
ans++;
//从开始选数的地方循环到 n
for (i = start; i <= n; i++)
//( 从下一个数开始选,已经选好数字的个数加一,并把这个数加上)
dfs(i + 1, cnt + 1, sum + a[i]);
}
int main(){
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
dfs(1, 0, 0);
cout << ans;
return 0;
}
P3612 [USACO17JAN] Secret Cow Code S
暴力枚举:创建两个超大一维数组,分别进行来回赋值,最后把需要的所有字母赋值到一个数组里,最后直接输出第 n 个位置的字母即可,但是这样做会超空间,只能得 40points:
#include<iostream>
using namespace std;
char ch[100000000];
char chx[100000000];
int main(){
int i = 0, cnt = 0;
scanf("%c", &ch[i]);
while (1) {
if (ch[i] == ' ')
break;
i++; cnt++;
scanf("%c", &ch[i]);
}
for (int i = 0; i < cnt; i++)
chx[i] = ch[i];
long long n, len; cin >> n;
len = n + 1 + cnt;
n--;
while (len > cnt) {
chx[cnt] = ch[cnt - 1];
for (int i = cnt + 1; i < 2 * cnt; i++)
chx[i] = ch[i - cnt - 1];
cnt *= 2;
for (int i = 0; i < cnt; i++)
ch[i] = chx[i];
}
cout << chx[n];
return 0;
}
因此需要采用分治和递归思想:
第一步还是通过 n 找 max:
long long max = 1;
long long n;
long long flag = n / cnt + 1;
while (max < flag)
max <<= 1;
max *= cnt;
第二步来判断 n 的类型,共有三种:
第一种:n 在右半部分的第一个位置,那么它在左半部分的位置就是最后一个,即:
n--;
第二种:n 在右半部分但是不在第一个位置,那么它在左半部分的位置就是减去一半的长度再减一,即:
n = n - (max >> 1) - 1;
第三种:n 在左半部分,这种情况直接长度减半即可:
max >>= 1;
最后输出即可
注意:>>n 是除以(2的n次方),<<n 是乘以(2的n次方),位运算相对会快些
#include<iostream>
using namespace std;
char ch[35];
int main(){
int i = 0, cnt = 0;
scanf("%c", &ch[i]);
while (1) {
if (ch[i] == ' ')
break;
i++; cnt++;
scanf("%c", &ch[i]);
}
long long max = 1; long long n; cin >> n;
long long flag = n / cnt + 1;
while (max < flag)
max <<= 1;
max *= cnt;
long long x = n - (max >> 1);
while (n > cnt) {
if (x == 1)
n--;
if (x > 1)
n = n - (max >> 1) - 1;
max >>= 1;
x = n - (max >> 1);
}
cout << ch[n - 1] << endl;
return 0;
}
P1010 [NOIP1998 普及组] 幂次方
#include <cmath> //其中有log2(x)和pow(x,y)函数
边分解边打印:
首先利用 log2() 将 n 分解出最大项 temp
接着判断 temp 的值,共三类值:temp==0,temp==1,temp > 1,其中前两种情况是直接打印即可,第三种情况通过递归打印
每一次判断打印结束,都要把 x 减去这一项的值,接着继续循环
注意:第一项是不需要 + 的,而后面的每一项都需要 +,因此需要 flag 来进行判断
#include<iostream>
#include<cmath>
using namespace std;
void show(int x) {
int flag = 0;
while (x != 0) {
int temp = int(log2(x));
if (flag == 1)
cout << "+";
if (temp == 1)
cout << "2";
else if (temp == 0)
cout << "2(0)";
else {
cout << "2(";
show(temp);
cout << ")";
}
x -= pow(2, temp);
flag = 1;
}
}
int main(){
int n; cin >> n;
show(n);
return 0;
}
P1498 南蛮图腾
这道题目数据很小,直接 模拟 来做的话,也是可以 AC 的:
首先创建一个大一点的二维数组,来存储字符:
char ch[2050][2050];
初始化为 “ 空 ” :
for (int i = 0; i < 2050; i++)
for (int j = 0; j < 2050; j++)
ch[i][j] = ' ';
把 n == 1 的图腾赋值:
需要注意的是:字符 ' \ ' 的赋值应该写成 ' \\ '
目的是:用于表示一个反斜杠,防止它被解释为一个转义序列符
ch[0][1] = '/', ch[0][2] = '\\';
ch[1][0] = '/', ch[1][1] = '_', ch[1][2] = '_', ch[1][3] = '\\';
即:
开始模拟:将上图往下平移,再往右下平移,即赋值操作:
for (int i = a; i <= b; i++)
for (int j = 0; j < b; j++)
ch[i][j] = ch[i - a][j];
for (int i = a; i <= b; i++)
for (int j = b; j < c; j++)
ch[i][j] = ch[i][j - b];
即:
接着把上方的字符清空:
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
if(ch[i][j]!=' ')
ch[i][j] = ' ';
即:
最后再把下方的左侧图腾再赋值到上方中间的位置:
for (int i = 0; i < a; i++)
for (int j = a; j < a + b; j++)
ch[i][j] = ch[i + a][j - a];
即:
#include<iostream>
#include<cmath>
using namespace std;
char ch[2050][2050];
void show(int n) {
int x = 1;
while (x < n) {
int a = pow(2, x), b = pow(2, x + 1), c = pow(2, x + 2);
for (int i = a; i <= b; i++)
for (int j = 0; j < b; j++)
ch[i][j] = ch[i - a][j];
for (int i = a; i <= b; i++)
for (int j = b; j < c; j++)
ch[i][j] = ch[i][j - b];
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
if(ch[i][j]!=' ')
ch[i][j] = ' ';
for (int i = 0; i < a; i++)
for (int j = a; j < a + b; j++)
ch[i][j] = ch[i + a][j - a];
x++;
}
}
int main(){
for (int i = 0; i < 2050; i++)
for (int j = 0; j < 2050; j++)
ch[i][j] = ' ';
ch[0][1] = '/', ch[0][2] = '\\';
ch[1][0] = '/', ch[1][1] = '_', ch[1][2] = '_', ch[1][3] = '\\';
int n; cin >> n;
show(n);
int high = pow(2, n);
int len = pow(2, n + 1);
for (int i = 0; i < high; i++) {
for (int j = 0; j < len; j++) {
cout << ch[i][j];
}
cout << endl;
}
return 0;
}
P1928 外星密码
这道题目直接 模拟 来做的话,也是可以 AC 的:
以输入 AC [ 2E [ 3CD ] [ 2B ] ] YU [ 3R ] 为例模拟一次:
字符串中从0开始遍历找第一个 ] ,再从该位置向左找第一个 [
得:AC [ 2E [ 3CD ] [ 2B ] ] YU [ 3R ]
记录数字 3 ,创建临时字符串 CD ,
将字符串中 [ ] 的部分删除,得 AC [ 2E [ 2B ] ] YU [ 3R ]
再把临时字符串加到原字符串中,得:AC [ 2ECDCDCD[ 2B ] ] YU [ 3R ]
这样第一次模拟就完成了
#include<iostream>
using namespace std;
string str = "";
int len, l, r;
//判断函数,当字符串无需解压缩时返回1,需要解压缩时返回0
int judge(string a) {
for (int i = 0; i < a.size(); i++)
if (a[i] == '[')
return 0;
return 1;
}
//模拟解压缩函数
string jieyasuo(string s) {
len = s.size();
for (int i = 0; i < len; i++) {
if (s[i] == ']') {
//找到 ] 的位置
r = i;
for (int j = r; j >= 0; j--) {
if (s[j] == '[') {
//找到 [ 的位置
l = j;
int cnt = 0;
int ll = l;
//判断数字位数,并且记录数字
if (s[j + 2] >= '0' && s[j + 2] <= '9') {
cnt = 10 * (s[j + 1] - '0') + (s[j + 2] - '0');
ll += 2;
}
else {
cnt = (s[j + 1] - '0');
ll += 1;
}
//创建临时字符串
string temp = "";
for (int k = ll + 1; k < r; k++)
temp += s[k];
//清除原字符串需要解压缩的部分
s.erase(l, r - l + 1);
//开始解压缩
while (cnt--) {
s.insert(l, temp);
}
//清除临时字符串
temp.clear();
//返回解压后的字符串
return s;
}
}
}
}
}
int main() {
cin >> str;
while (judge(str) != 1)
str = jieyasuo(str);
cout << str << endl;
return 0;
}
P1990 覆盖墙壁
这题目最重要的就是推出递推公式:
化简:
因此最后的递推公式为:
f[i] = 2 * f[i - 1] + f[i - 3] ;
注意:题目要求最多输出四位,因此每次在递推的同时,对数组 f [ i ] % 10000 即可
#include<iostream>
using namespace std;
int n;
int f[1000005];
int main() {
cin >> n;
f[1] = 1, f[2] = 2, f[3] = 5;
if (n >= 4)
for (int i = 4; i <= n; i++) {
f[i] = 2 * (f[i - 1] % 10000) + f[i - 3] % 10000;
f[i] %= 10000;
}
cout << f[n];
return 0;
}
P1259 黑白棋子的移动
这个题目测试数据较小,纯模拟是可以 AC 的,以样例为例进行分析:n = 7
o o o o o o o * * * * * * * - - 交换该行的红色部分后得到下一行 o o o o o o - - * * * * * * o * 交换该行的红色部分后得到下一行 o o o o o o * * * * * * - - o * 交换该行的红色部分后得到下一行 o o o o o - - * * * * * o * o * 交换该行的红色部分后得到下一行 o o o o o * * * * * - - o * o * 交换该行的红色部分后得到下一行 o o o o - - * * * * o * o * o * 交换该行的红色部分后得到下一行 o o o o * * * * - - o * o * o * 交换该行的红色部分后得到下一行 o o o - - * * * o * o * o * o * 最后四行没有明显的规律,可放到最后进行依次输出 o o o * o * * - - * o * o * o * o - - * o * * o o * o * o * o * o * o * o * - - o * o * o * o * - - o * o * o * o * o * o * o *
而上面的规律就是:
如果第一个 o* 在 -- 的左边,则将两者交换即可
如果第一个 o* 在 -- 的右边,则将 -- 和最后两个 ** 交换即可
#include<iostream>
using namespace std;
int n;
char chess[205];
void last() { //打印最后没有规律的字符串
int temp;
temp = n - 4;
cout << "ooo*o**--*";
while (temp--)
cout << "o*";
cout << endl;
temp = n - 4;
cout << "o--*o**oo*";
while (temp--)
cout << "o*";
cout << endl;
temp = n - 4;
cout << "o*o*o*--o*";
while (temp--)
cout << "o*";
cout << endl;
temp = n - 4;
cout << "--o*o*o*o*";
while (temp--)
cout << "o*";
cout << endl;
}
void show(char a[], int cnt) { //打印字符串函数
for (int i = 1; i <= cnt; i++)
cout << a[i];
cout << endl;
}
void move(char a[], int cnt) { //模拟交换函数(即规律)
int flag = 1;
int key = 1;
for (int i = 1; i <= cnt - 1; i++)
if (a[i] == '-' && a[i + 1] == '-')
flag = i;
for (int i = 1; i <= cnt - 1; i++) {
if (a[i] == 'o' && a[i + 1] == '*') {
key = i;
break;
}
}
if (key < flag) {
a[flag] = a[key], a[flag + 1] = a[key + 1];
a[key] = '-', a[key + 1] = '-';
}
else {
a[flag] = '*', a[flag + 1] = '*';
a[key - 1] = '-', a[key - 2] = '-';
}
}
int main() {
cin >> n;
int len = n * 2 + 2;
//初始化chess数组
for (int i = 1; i <= n; i++)
chess[i] = 'o';
for (int i = n + 1; i <= 2 * n; i++)
chess[i] = '*';
chess[2 * n + 1] = '-', chess[2 * n + 2] = '-';
//先进行第一次打印
show(chess, len);
//开始规律模拟,依次调用函数,进行规律输出
int temp = 2 * (n - 4) + 1;
while (temp--) {
move(chess, len);
show(chess, len);
}
//最后几行没有规律,直接输出
last();
return 0;
}
P1228 地毯填补问题
分治思想:
以题例为例:先将 n*n 分成4个 (n/2)*(n/2) 的区域
接着判断公主的位置,为左上区域,故选择一号毛毯进行填充,并且输出一号毛毯的坐标
然后4个小区域分别进行递归:
左上区域中包含公主,故公主位置不变
右上区域中被一号毛毯覆盖一个位置(4,5),故此位置就是该区域的公主位置
左下区域中被一号毛毯覆盖一个位置(5,4),故此位置就是该区域的公主位置
右下区域中被一号毛毯覆盖一个位置(5,5),故此位置就是该区域的公主位置
最后毛毯可被覆盖成功:
#include<iostream>
#include<cmath>
using namespace std;
int k, x, y;
void dfs(int a, int b, int n, int x, int y) {
if (n == 1) // n == 1 时直接退出
return;
n /= 2; //每次将 n*n 拆成4个 (n/2)*(n/2) 的区域
if (x <= a + n - 1 && y <= b + n - 1) {
//公主在左上方包括边界
cout << a + n << " " << b + n << " 1" << endl; //输出
dfs(a, b, n, x, y); //递归左上区域(公主位置不变)
dfs(a, b + n, n, a + n - 1, b + n);//递归右上区域
dfs(a + n, b, n, a + n, b + n - 1);//递归左下区域
dfs(a + n, b + n, n, a + n, b + n);//递归右下区域
}
else if (x <= a + n - 1 && y >= b + n) {
//公主在右上方包括边界
cout << a + n << " " << b + n - 1 << " 2" << endl; //输出
dfs(a, b, n, a + n - 1, b + n - 1);//递归左上区域
dfs(a, b + n, n, x, y); //递归右上区域(公主位置不变)
dfs(a + n, b, n, a + n, b + n - 1);//递归左下区域
dfs(a + n, b + n, n, a + n, b + n);//递归右下区域
}
else if (x >= a + n && y <= b + n - 1) {
//公主在左下方包括边界
cout << a + n - 1 << " " << b + n << " 3" << endl; //输出
dfs(a, b, n, a + n - 1, b + n - 1);//递归左上区域
dfs(a, b + n, n, a + n - 1, b + n);//递归右上区域
dfs(a + n, b, n, x, y); //递归左下区域(公主位置不变)
dfs(a + n, b + n, n, a + n, b + n);//递归右下区域
}
else {
//公主在右下方包括边界
cout << a + n - 1 << " " << b + n - 1 << " 4" << endl; //输出
dfs(a, b, n, a + n - 1, b + n - 1);//递归左上区域
dfs(a, b + n, n, a + n - 1, b + n);//递归右上区域
dfs(a + n, b, n, a + n, b + n - 1);//递归左下区域
dfs(a + n, b + n, n, x, y); //递归右下区域(公主位置不变)
}
return;
}
int main() {
cin >> k;
int n = pow(2, k);
cin >> x >> y;
//从 (1,1) 开始到 (n,n) 此时公主为(x,y)
dfs(1, 1, n, x, y);
return 0;
}