QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#432948 | #7117. Quine | ucup-admin-3-1 | 100 ✓ | 1ms | 3572kb | C++23 | 13.9kb | 2024-06-07 21:08:33 | 2024-06-07 21:08:33 |
Judging History
answer
/*
ИНСТРУКЦИЯ — КАК НАПИСАТЬ КУАЙН
Мы будем всё делать на сайте
https://godbolt.org на языке C++ (именно
он открывается на этом сайте по
умолчанию).
Начнём с заготовки следующего вида:
#include <iostream>
#include <string>
const std::string s = "@";
int main() {
std::cout << s;
}
Проблема сейчас в том, что эта программа
выводит пустую строку. Если мы сейчас
возьмём эту программу, скопируем и вставим
меж кавычек, то код не скомпилируется
из-за того, что в тексте программы есть
кавычки, переводы строк и прочие символы,
которые надо экранировать. Давайте напишем
вспомогательную программу, которая читает
текст и выводит его как строковый литерал
в кавычках (то есть экранирует всё, что
требуется, для помещения этой строки в код
сторонней программы). Реализовать это
можно, например, так:
#include <iostream>
#include <string>
int main() {
std::string ans = "\"";
char c;
while (std::cin.get(c))
switch (c) {
case '\n':
ans += "\\n";
break;
case '\\':
ans += "\\\\";
break;
case '"':
ans += "\\\"";
break;
default:
ans += c;
}
ans += '"';
std::cout << ans;
}
Я сохранил эту программу по адресу:
https://godbolt.org/z/TeMM6csxr
После того, как я допишу этот комментарий,
я хочу попробовать взять всё содержимое
этой программы, выделить, скопировать и
вставить на место кавычек. Но квайна не
получится, так как на месте программы всё
ещё будут пустые кавычки.
Давайте сформулируем наш алгоритм:
1) написать программу, в которой
объявлена строковая переменная, которая
должна будет хранить исходный код, но
которая пока что инициализирована
пустой строкой;
2) выделить всю эту программу, скопировать
и вставить в вспомогательную программу;
3) выводом вспомогательной программы
заменить кавычки в исходной программе.
Если бы этот алгоритм исполняла сама
программа, а не мы вручную, то всё бы
идеально сработало!
Так давайте и напишем заготовку программы,
которая бы всё это делала сама:
#include <iostream>
#include <string>
std::string escape(const std::string& s) {
std::string ans;
char c;
for (char c : s)
switch (c) {
case '\n':
ans += "\\n";
break;
case '\\':
ans += "\\\\";
break;
case '"':
ans += "\\\"";
break;
default:
ans += c;
}
return ans;
}
const std::string s = "@";
int main() {
std::string output;
for (char c : s)
switch (c) {
case '@':
output += escape(s);
break;
default:
output += c;
}
std::cout << output;
}
Теперь дело за малым: скопировать всю
написанную тут программу в программу,
превращающую вход в строковый литерал,
и подставить её вывод вместо "@".
К сожалению, это не сработает: в нашей
программе более одного символа '@'.
Поэтому надо заменять '@' на код
программы аккуратно. В нашем случае
будет правильно сделать так: сделать
подстановку в тот символ '@', который
имеет второй номер с конца.
Заготовка получается такая:
#include <iostream>
#include <string>
std::string escape(const std::string& s) {
std::string ans;
char c;
for (char c : s)
switch (c) {
case '\n':
ans += "\\n";
break;
case '\\':
ans += "\\\\";
break;
case '"':
ans += "\\\"";
break;
default:
ans += c;
}
return ans;
}
const std::string s = "@";
int main() {
int cnt = 0;
int at;
for (at = s.size() - 1; at >= 0; --at) {
if (s[at] == '@')
++cnt;
if (cnt == 2)
break;
}
std::string output = s.substr(0, at)
+ escape(s)
+ s.substr(at + 1);
std::cout << output;
}
Снова скопируем этот код во
вспомогательную программу, её выводом
проинициализируем s. Это уже работает:
можно у полученного нами квайна сравнить
вывод и код с помощью веб-сервиса,
например, https://www.diffchecker.com.
*/
#include <iostream>
#include <string>
std::string escape(const std::string& s) {
std::string ans;
char c;
for (char c : s)
switch (c) {
case '\n':
ans += "\\n";
break;
case '\\':
ans += "\\\\";
break;
case '"':
ans += "\\\"";
break;
default:
ans += c;
}
return ans;
}
const std::string s = "/*\nИНСТРУКЦИЯ — КАК НАПИСАТЬ КУАЙН\n\nМы будем всё делать на сайте\nhttps://godbolt.org на языке C++ (именно\nон открывается на этом сайте по\nумолчанию).\n\nНачнём с заготовки следующего вида:\n\n#include <iostream>\n#include <string>\n\nconst std::string s = \"@\";\n\nint main() {\n std::cout << s;\n}\n\nПроблема сейчас в том, что эта программа\nвыводит пустую строку. Если мы сейчас\nвозьмём эту программу, скопируем и вставим\nмеж кавычек, то код не скомпилируется\nиз-за того, что в тексте программы есть\nкавычки, переводы строк и прочие символы,\nкоторые надо экранировать. Давайте напишем\nвспомогательную программу, которая читает\nтекст и выводит его как строковый литерал\nв кавычках (то есть экранирует всё, что\nтребуется, для помещения этой строки в код\nсторонней программы). Реализовать это\nможно, например, так:\n\n#include <iostream>\n#include <string>\n\nint main() {\n std::string ans = \"\\\"\";\n char c;\n while (std::cin.get(c))\n switch (c) {\n case '\\n':\n ans += \"\\\\n\";\n break;\n case '\\\\':\n ans += \"\\\\\\\\\";\n break;\n case '\"':\n ans += \"\\\\\\\"\";\n break;\n default:\n ans += c;\n }\n ans += '\"';\n std::cout << ans;\n}\n\nЯ сохранил эту программу по адресу:\nhttps://godbolt.org/z/TeMM6csxr\n\nПосле того, как я допишу этот комментарий,\nя хочу попробовать взять всё содержимое\nэтой программы, выделить, скопировать и\nвставить на место кавычек. Но квайна не\nполучится, так как на месте программы всё\nещё будут пустые кавычки.\n\nДавайте сформулируем наш алгоритм:\n1) написать программу, в которой\n объявлена строковая переменная, которая\n должна будет хранить исходный код, но\n которая пока что инициализирована\n пустой строкой;\n2) выделить всю эту программу, скопировать\n и вставить в вспомогательную программу;\n3) выводом вспомогательной программы\n заменить кавычки в исходной программе.\nЕсли бы этот алгоритм исполняла сама\nпрограмма, а не мы вручную, то всё бы\nидеально сработало!\nТак давайте и напишем заготовку программы,\nкоторая бы всё это делала сама:\n\n#include <iostream>\n#include <string>\n\nstd::string escape(const std::string& s) {\n std::string ans;\n char c;\n for (char c : s)\n switch (c) {\n case '\\n':\n ans += \"\\\\n\";\n break;\n case '\\\\':\n ans += \"\\\\\\\\\";\n break;\n case '\"':\n ans += \"\\\\\\\"\";\n break;\n default:\n ans += c;\n }\n return ans;\n}\n\nconst std::string s = \"@\";\n\nint main() {\n std::string output;\n for (char c : s)\n switch (c) {\n case '@':\n output += escape(s);\n break;\n default:\n output += c;\n }\n std::cout << output;\n}\n\nТеперь дело за малым: скопировать всю\nнаписанную тут программу в программу,\nпревращающую вход в строковый литерал,\nи подставить её вывод вместо \"@\".\n\nК сожалению, это не сработает: в нашей\nпрограмме более одного символа '@'.\nПоэтому надо заменять '@' на код\nпрограммы аккуратно. В нашем случае\nбудет правильно сделать так: сделать\nподстановку в тот символ '@', который\nимеет второй номер с конца.\nЗаготовка получается такая:\n\n#include <iostream>\n#include <string>\n\nstd::string escape(const std::string& s) {\n std::string ans;\n char c;\n for (char c : s)\n switch (c) {\n case '\\n':\n ans += \"\\\\n\";\n break;\n case '\\\\':\n ans += \"\\\\\\\\\";\n break;\n case '\"':\n ans += \"\\\\\\\"\";\n break;\n default:\n ans += c;\n }\n return ans;\n}\n\nconst std::string s = \"@\";\n\nint main() {\n int cnt = 0;\n int at;\n for (at = s.size() - 1; at >= 0; --at) {\n if (s[at] == '@')\n ++cnt;\n if (cnt == 2)\n break;\n }\n std::string output = s.substr(0, at)\n + escape(s)\n + s.substr(at + 1);\n std::cout << output;\n}\n\nСнова скопируем этот код во\nвспомогательную программу, её выводом\nпроинициализируем s. Это уже работает:\nможно у полученного нами квайна сравнить\nвывод и код с помощью веб-сервиса,\nнапример, https://www.diffchecker.com.\n*/\n\n#include <iostream>\n#include <string>\n\nstd::string escape(const std::string& s) {\n std::string ans;\n char c;\n for (char c : s)\n switch (c) {\n case '\\n':\n ans += \"\\\\n\";\n break;\n case '\\\\':\n ans += \"\\\\\\\\\";\n break;\n case '\"':\n ans += \"\\\\\\\"\";\n break;\n default:\n ans += c;\n }\n return ans;\n}\n\nconst std::string s = \"@\";\nint main() {\n int cnt = 0;\n int at;\n for (at = s.size() - 1; at >= 0; --at) {\n if (s[at] == '@')\n ++cnt;\n if (cnt == 2)\n break;\n }\n std::string output = s.substr(0, at)\n + escape(s)\n + s.substr(at + 1);\n std::cout << output;\n}\n";
int main() {
int cnt = 0;
int at;
for (at = s.size() - 1; at >= 0; --at) {
if (s[at] == '@')
++cnt;
if (cnt == 2)
break;
}
std::string output = s.substr(0, at)
+ escape(s)
+ s.substr(at + 1);
std::cout << output;
}
詳細信息
Test #1:
score: 100
Accepted
time: 1ms
memory: 3572kb
input:
output:
/* ИНСТРУКЦИЯ — КАК НАПИСАТЬ КУАЙН Мы будем всё делать на сайте https://godbolt.org на языке C++ (именно он открывается на этом сайте по умолчанию). Начнём с заготовки следующего вида: #include <iostream> #include <string> const std::string s = "@"; int main() { std::cout << s; } Проблема ...
result:
ok 221 lines