题解:P14518 [NFLSPC #8] APLSPC

· · 题解

P14518 [NFLSPC #8] APLSPC

毒瘤题!

我竟然能写黑题题解了!

本题由 @_Mortis_、@LuoXH 和 @xzy_caiji 在机房共同讨论完成,本蒟蒻仅将思路整理后写成题解。

题意

我们需要编写一个程序,要求:

  1. 不含任何 C++ 和 python 的关键字
  2. 在 C++ 和 python 语言下都能输出自身(不过滤换行)

思路

2pts

该部分要求程序能在 C++ 运行下输出自身。

正常的程序想要输出自身只会无限套娃,因为输出自己的部分需要再次输出,比如:。

main(){char*s="main(){char*s=...;__builtin_printf(s);}";__builtin_printf(s);}

这时我们只需要将省略号部分改为 %c%s%c,在 __builtin_printf 的参数后添加 34,s,3434 为引号),相当于省略号部分就是自身。这样我们就利用 printf 的格式化输出解决了这个问题。

:::warning[注意]{open} 代码不能含有关键字 char

我们需要利用 define 的特性:在 char 中间加上 ## 变成 ch##ar 并不影响编译。如:#define c ch##ar。 :::

最终得到 2pts 代码:

#define c ch##ar
main(){c*s="#define c ch##ar%cmain(){c*s=%c%s%c;__builtin_printf(s,10,34,s,34);}";__builtin_printf(s,10,34,s,34);}

10pts

这部分要求代码在 python 下也能编译通过,还是比较容易的。

注意到 #define 中的 # 在 python 中恰好是注释。

那么我们可以将代码全 defineprint 这种在 python 中可以编译的函数。

10 pts 代码:

#define c ch##ar
#define print c*s="#define c ch##ar%c#define print c*s=%c%s%c;main(){__builtin_printf(s,10,34,s,34,10);}%cprint";main(){__builtin_printf(s,10,34,s,34,10);}
print
#define c ch##ar
#define print c*s="#define c ch##ar%c#define print c*s=%c%s%c;main(){__builtin_printf(s,10,34,s,34,10);}%cprint";main(){__builtin_printf(s,10,34,s,34,10);}
print

100pts

与 C++ 类似,在 python 中能输出自己的代码长这样(加上 end= 是为了避免换行):

I="I=%c%s%c%cprint(end=I%%(34,I,34,10))"
print(end=I%(34,I,34,10))

我们又发现,在 C++ 中,定义变量时变量类型和变量名之间是可以换行的,如:

char
c;

那么,一个基本思路就出来了:将变量类型 define 成 python 的函数,按上面的方法换行写,就能实现在 C++ 和 python 中同时定义一个字符串;将 C++ 中的主函数 defineprint,就能实现输出!

一个不知道多少分的代码:

#define id ch##ar*
#define print(a) main(){__builtin_printf(I,10,10,10,34,I,34);}
id
I="#define id ch##ar*%c#define print(a) main(){__builtin_printf(I,10,10,10,34,I,34);}%cid%cI=%c%s%c;print(end=I%%(10,10,10,34,I,34))";print(end=I%(10,10,10,34,I,34))
#define id ch##ar*
#define print(a) main(){__builtin_printf(I,10,10,10,34,I,34);}
id
I="#define id ch##ar*%c#define print(a) main(){__builtin_printf(I,10,10,10,34,I,34);}%cid%cI=%c%s%c;print(end=I%%(10,10,10,34,I,34))";print(end=I%(10,10,10,34,I,34))

253b。

我们发现 print(a) 后的空格可以去掉。这样代码长度来到了 251b,99pts。

最后,@LuoXH 发现 char* 可以用 auto 代替。省下 2b,100pts。

最终代码(燃尽了):

#define id au##to
#define print(a)main(){__builtin_printf(I,10,10,10,34,I,34);}
id
I="#define id au##to%c#define print(a)main(){__builtin_printf(I,10,10,10,34,I,34);}%cid%cI=%c%s%c;print(end=I%%(10,10,10,34,I,34))";print(end=I%(10,10,10,34,I,34))
#define id au##to
#define print(a)main(){__builtin_printf(I,10,10,10,34,I,34);}
id
I="#define id au##to%c#define print(a)main(){__builtin_printf(I,10,10,10,34,I,34);}%cid%cI=%c%s%c;print(end=I%%(10,10,10,34,I,34))";print(end=I%(10,10,10,34,I,34))