题解:P14518 [NFLSPC #8] APLSPC
首先 Quine 大家都会吧?不会的可以去做 LOJ #4 或 UOJ #8。
::::success[code]{open} :::success[C++]
char*s="char*s=%c%s%c;main(){__builtin_printf(s,34,s,34);}";main(){__builtin_printf(s,34,s,34);}
通过 printf 输出 %s 来避免无限套娃。
:::
:::success[Python]
s='s=%r;print(s%%s)';print(s%s)
类似 C++,但是用 %r 可以直接把字符串连同引号输出,规避掉引号的问题。
这个能过 UOJ,LOJ 过不了因为多换行,但是我们先忽略这个问题。 ::: ::::
接下来看 #define 在 Python 中,因为开头是 #,所以会被无视。这启发我们把整段代码 #define 成 print 之类的在 python 可以过编的东西。
但是我们还有一个 char 关键字,怎么办呢?
正好 #define 有一个特性:如果出现 ## 则直接把两端的东西拼接起来。例如,#define f(a,b) a##b 后 f(w,1) 等价于 w1。所以我们也可以用 ## 把 char 拆成 ch##ar。
::::success[code]
#define print ch##ar*s="#define print ch##ar*s=%c%s%c;main(){__builtin_printf(s,34,s,34,10);}%cprint";main(){__builtin_printf(s,34,s,34,10);}
print
:::info[Python 渲染]
#define print char*s="#define print char*s=%c%s%c;main(){__builtin_printf(s,34,s,34,10);}%cprint";main(){__builtin_printf(s,34,s,34,10);}
print
:::
注意换行也要在 printf 中用 ASCII 输出。
::::
接下来考虑正解。
先考虑把 Python 的 print 放进代码里。C++23 倒是有个函数叫 std::print,但是 C++ 肯定不支持 Python 的字符串 S%(34,S,34,10) 格式,所以最好的方式是把它注释掉。
又注意到,// 在 Python 中是一个正常的运算符,所以可以通过 1//1 等方式让 C++ 认为后面被注释掉,但是 Python 中没有效果。
此外我们还需要在 Python 中定义整份代码为一个字符串。不难想到,可以 #define 掉 C++ 中 char*s 前面的部分,例如变成 S,这样在 Python 中就相当于定义了一个字符串 S 了。
定义字符串之后的 C++ 输出语句在 Python 中是不兼容的,所以肯定要用 #define 注释掉。我们可以把这一段也 #define 成 S,这样后面单写一个 S 在 Python 就完全没有问题了,相比上面的 print 省了不少代码长度。
最后一个问题:Python 的 print 会多换行,怎么办呢?
通常来说会用 print(...,end='') 来干掉换行,但是在本题代码长度就爆了。
我们注意到,print 的第一个参数可以为空,而把 end 赋值为我们要输出的东西是不会多换行的。所以使用 print(end=S%(...)) 即可。
展示最终成果! :::success[code] C++ 渲染:
#define S main(){ch##ar*s
S="#define S main(){ch##ar*s%cS=%c%s%c;1//1;print(end=S%%(10,34,S,34,10,10))%c#define S;__builtin_printf(s,10,34,s,34,10,10);}%cS";1//1;print(end=S%(10,34,S,34,10,10))
#define S;__builtin_printf(s,10,34,s,34,10,10);}
S
Python 渲染:
#define S main(){ch##ar*s
S="#define S main(){ch##ar*s%cS=%c%s%c;1//1;print(end=S%%(10,34,S,34,10,10))%c#define S;__builtin_printf(s,10,34,s,34,10,10);}%cS";1//1;print(end=S%(10,34,S,34,10,10))
#define S;__builtin_printf(s,10,34,s,34,10,10);}
S
247 Bytes,几乎卡满。 :::