結果

問題 No.5006 Hidden Maze
ユーザー takumi152
提出日時 2022-06-12 19:01:53
言語 C++17(gcc12)
(gcc 12.3.0 + boost 1.87.0)
結果
AC  
実行時間 123 ms / 2,000 ms
コード長 13,172 bytes
コンパイル時間 2,959 ms
実行使用メモリ 22,888 KB
スコア 86,389
平均クエリ数 137.11
最終ジャッジ日時 2022-06-12 19:02:04
合計ジャッジ時間 10,506 ms
ジャッジサーバーID
(参考情報)
judge16 / judge11
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#pragma GCC target ("avx2")
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <utility>
#include <string>
#include <queue>
#include <stack>
#include <unordered_set>
#include <random>
#include <cmath>
#include <cassert>
#include <x86intrin.h>
struct xorshift64 {
unsigned long long int x = 88172645463325252ULL;
inline unsigned short nextUShort() {
x = x ^ (x << 7);
return x = x ^ (x >> 9);
}
inline unsigned int nextUShortMod(unsigned long long int mod) {
x = x ^ (x << 7);
x = x ^ (x >> 9);
return ((x & 0x0000ffffffffffff) * mod) >> 48;
}
inline unsigned int nextUInt() {
x = x ^ (x << 7);
return x = x ^ (x >> 9);
}
inline unsigned int nextUIntMod(unsigned long long int mod) {
x = x ^ (x << 7);
x = x ^ (x >> 9);
return ((x & 0x00000000ffffffff) * mod) >> 32;
}
inline unsigned long long int nextULL() {
x = x ^ (x << 7);
return x = x ^ (x >> 9);
}
inline double nextDouble() {
x = x ^ (x << 7);
x = x ^ (x >> 9);
return (double)x * 5.42101086242752217e-20;
}
};
struct timer {
double t = 0.0;
double lastStop = 0.0;
bool stopped = false;
timer() {
restart();
}
inline void restart() {
t = now();
stopped = false;
}
inline void start() {
if (stopped) {
t += now() - lastStop;
stopped = false;
}
}
inline void stop() {
if (!stopped) {
lastStop = now();
stopped = true;
}
}
inline double time() {
if (stopped) return lastStop - t;
else return now() - t;
}
inline double now() {
unsigned long long l, h;
__asm__ ("rdtsc" : "=a"(l), "=d"(h));
#ifdef LOCAL
return (double)(l | h << 32) * 2.857142857142857e-10; // 1 / 3.5e9, for local (Ryzen 9 3950X)
#else
//return (double)(l | h << 32) * 3.5714285714285715e-10; // 1 / 2.8e9, for AWS EC2 C3 (Xeon E5-2680 v2)
//return (double)(l | h << 32) * 3.4482758620689656e-10; // 1 / 2.9e9, for AWS EC2 C4 (Xeon E5-2666 v3)
return (double)(l | h << 32) * 3.333333333333333e-10; // 1 / 3.0e9, for AWS EC2 C5 (Xeon Platinum 8124M / Xeon Platinum 8275CL)
#endif
}
};
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef pair<int, int> Pii;
const ll mod = 1000000007;
timer theTimer;
xorshift64 theRandom;
mt19937 theMersenne(1);
// hyper parameters
// structs
struct {
const vector<int> x = { -1, 1, 0, 0};
const vector<int> y = { 0, 0, -1, 1};
const vector<char> c = {'U', 'D', 'L', 'R'};
} delta;
// constants
constexpr int h = 20;
constexpr int w = 20;
constexpr int turn_limit = 1001;
constexpr int start_x = 0;
constexpr int start_y = 0;
constexpr int finish_x = h-1;
constexpr int finish_y = w-1;
vector<double> edge_cost;
// inputs
double p;
// outputs
string ans;
// internals
vector<vector<bool> > edge_passable_vertical;
vector<vector<bool> > edge_passable_horizontal;
vector<vector<int> > edge_wall_hit_count_vertical;
vector<vector<int> > edge_wall_hit_count_horizontal;
#ifdef LOCAL_TEST
vector<vector<bool> > wall_vertical;
vector<vector<bool> > wall_horizontal;
vector<int> movable_count;
#endif
bool within_board(int x, int y) {
return 0 <= x && x < h && 0 <= y && y < w;
}
void receive_first_input() {
#ifndef LOCAL_TEST
int _h, _w, _p;
cin >> _h >> _w >> _p;
p = (double) _p * 0.01;
#else
p = 0.15;
unsigned long long int x;
cin >> x;
theRandom.x = x;
// random_device rng;
// theRandom.x = ((unsigned long long int) rng() << 32) | (unsigned long long int) rng();
#endif
}
int answer(string ans, int turn_count) {
#ifndef LOCAL_TEST
cout << ans << endl;
#endif
int res;
#ifndef LOCAL_TEST
cin >> res;
#else
if (turn_count >= turn_limit - 1) res = -1;
else {
bool wall_hit = false;
int px = start_x;
int py = start_y;
for (int i = 0; i < (int) ans.size(); i++) {
if (i == movable_count[turn_count]) {
wall_hit = true;
res = i;
break;
}
for (int d = 0; d < 4; d++) {
if (delta.c[d] == ans[i]) {
if (d & 2) {
// horizontal movement
assert(delta.x[d] == 0);
assert(abs(delta.y[d]) == 1);
int wall_y = min(py, py + delta.y[d]);
if (wall_horizontal[px + delta.x[d]][wall_y]) {
wall_hit = true;
res = i;
break;
}
}
else {
// vertical movement
assert(abs(delta.x[d]) == 1);
assert(delta.y[d] == 0);
int wall_x = min(px, px + delta.x[d]);
if (wall_vertical[wall_x][py + delta.y[d]]) {
wall_hit = true;
res = i;
break;
}
}
px += delta.x[d];
py += delta.y[d];
}
}
if (wall_hit) break;
}
if (!wall_hit && px == finish_x && py == finish_y) {
res = -1;
}
else if (!wall_hit) {
res = ans.size();
}
}
// cerr << setw(4) << turn_count << " " << setw(4) << res << " " << setw(4) << movable_count[turn_count] << " " << ans << endl;
#endif
return res;
}
void init() {
edge_cost = vector<double>(turn_limit);
edge_cost[0] = 1.0;
for (int i = 1; i < turn_limit; i++) {
edge_cost[i] = edge_cost[i-1] * (1.0 / p);
}
edge_passable_vertical = vector<vector<bool> >(h-1, vector<bool>(w));
edge_passable_horizontal = vector<vector<bool> >(h, vector<bool>(w-1));
edge_wall_hit_count_vertical = vector<vector<int> >(h-1, vector<int>(w));
edge_wall_hit_count_horizontal = vector<vector<int> >(h, vector<int>(w-1));
#ifdef LOCAL_TEST
wall_vertical = vector<vector<bool> >(h-1, vector<bool>(w));
wall_horizontal = vector<vector<bool> >(h, vector<bool>(w-1));
int m = theRandom.nextUIntMod(101) + 100;
int wall_created = 0;
while (wall_created < m) {
int wall_dir = theRandom.nextUIntMod(2);
int wall_x, wall_y;
if (wall_dir == 0) {
wall_x = theRandom.nextUIntMod(h);
wall_y = theRandom.nextUIntMod(w-1);
if (wall_horizontal[wall_x][wall_y]) continue;
wall_horizontal[wall_x][wall_y] = true;
}
else {
wall_x = theRandom.nextUIntMod(h-1);
wall_y = theRandom.nextUIntMod(w);
if (wall_vertical[wall_x][wall_y]) continue;
wall_vertical[wall_x][wall_y] = true;
}
vector<vector<bool> > visited(h, vector<bool>(w));
queue<tuple<int, int> > que;
que.emplace(start_x, start_y);
while (!que.empty()) {
auto [px, py] = que.front();
que.pop();
if (visited[px][py]) continue;
visited[px][py] = true;
for (int d = 0; d < 4; d++) {
if (within_board(px + delta.x[d], py + delta.y[d]) && !visited[px + delta.x[d]][py + delta.y[d]]) {
if (d & 2) {
// horizontal movement
assert(delta.x[d] == 0);
assert(abs(delta.y[d]) == 1);
int wall_y = min(py, py + delta.y[d]);
if (!wall_horizontal[px + delta.x[d]][wall_y]) {
que.emplace(px + delta.x[d], py + delta.y[d]);
}
}
else {
// vertical movement
assert(abs(delta.x[d]) == 1);
assert(delta.y[d] == 0);
int wall_x = min(px, px + delta.x[d]);
if (!wall_vertical[wall_x][py + delta.y[d]]) {
que.emplace(px + delta.x[d], py + delta.y[d]);
}
}
}
}
}
bool all_reachable = true;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (!visited[i][j]) {
all_reachable = false;
break;
}
}
if (!all_reachable) break;
}
if (all_reachable) wall_created++;
else {
if (wall_dir == 0) {
wall_horizontal[wall_x][wall_y] = false;
}
else {
wall_vertical[wall_x][wall_y] = false;
}
}
}
movable_count = vector<int>(turn_limit);
for (int i = 0; i < turn_limit; i++) {
for (int x = 0; x < 400; x++) {
int c = theRandom.nextUIntMod(100);
movable_count[i]++;
if ((double) c < p * 100.0 - 0.5) break;
}
}
#endif
}
void solve() {
for (int turn_count = 0; turn_count < turn_limit; turn_count++) {
// find next path
string next_path = "";
{
vector<vector<char> > prev_dir(h, vector<char>(w)); // direction to start
vector<vector<bool> > visited(h, vector<bool>(w));
priority_queue<tuple<double, int, int, char>, vector<tuple<double, int, int, char> >, greater<tuple<double, int, int, char> > > que;
que.emplace(0, start_x, start_y, '.');
while (!que.empty()) {
auto [current_cost, px, py, dir] = que.top();
que.pop();
if (visited[px][py]) continue;
visited[px][py] = true;
prev_dir[px][py] = dir;
if (px == finish_x && py == finish_y) break;
for (int d = 0; d < 4; d++) {
if (within_board(px + delta.x[d], py + delta.y[d]) && !visited[px + delta.x[d]][py + delta.y[d]]) {
double penalty = (d & 1 ? edge_cost[1] : 0.0); // penalize U/L
if (d & 2) {
// horizontal movement
assert(delta.x[d] == 0);
assert(abs(delta.y[d]) == 1);
int wall_y = min(py, py + delta.y[d]);
if (edge_passable_horizontal[px + delta.x[d]][wall_y]) {
que.emplace(current_cost + (penalty + theRandom.nextDouble() * 0.001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py +
                    delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip
}
else {
que.emplace(current_cost + (penalty + edge_cost[edge_wall_hit_count_horizontal[px + delta.x[d]][wall_y]] + theRandom.nextDouble() * 0
                    .001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py + delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip
}
}
else {
// vertical movement
assert(abs(delta.x[d]) == 1);
assert(delta.y[d] == 0);
int wall_x = min(px, px + delta.x[d]);
if (edge_passable_vertical[wall_x][py + delta.y[d]]) {
que.emplace(current_cost + (penalty + theRandom.nextDouble() * 0.001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py +
                    delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip
}
else {
que.emplace(current_cost + (penalty + edge_cost[edge_wall_hit_count_vertical[wall_x][py + delta.y[d]]] + theRandom.nextDouble() * 0
                    .001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py + delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip
}
}
}
}
}
{
int px = finish_x;
int py = finish_y;
while (!(px == start_x && py == start_y)) {
assert(within_board(px, py));
assert(visited[px][py]);
visited[px][py] = false;
auto dir = prev_dir[px][py];
for (int d = 0; d < 4; d++) {
if (delta.c[d] == dir) {
next_path.push_back(delta.c[d ^ 1]);
px += delta.x[d];
py += delta.y[d];
break;
}
}
}
reverse(next_path.begin(), next_path.end());
}
}
auto res = answer(next_path, turn_count);
if (res == -1) {
// valid path found
cerr << "Score = " << turn_limit - turn_count - 1 << endl;
break;
}
else {
int px = 0;
int py = 0;
for (int i = 0; i < res; i++) {
for (int d = 0; d < 4; d++) {
if (delta.c[d] == next_path[i]) {
if (d & 2) {
// horizontal movement
assert(delta.x[d] == 0);
assert(abs(delta.y[d]) == 1);
int wall_y = min(py, py + delta.y[d]);
edge_passable_horizontal[px + delta.x[d]][wall_y] = true;
}
else {
// vertical movement
assert(abs(delta.x[d]) == 1);
assert(delta.y[d] == 0);
int wall_x = min(px, px + delta.x[d]);
edge_passable_vertical[wall_x][py + delta.y[d]] = true;
}
px += delta.x[d];
py += delta.y[d];
}
}
}
for (int d = 0; d < 4; d++) {
if (delta.c[d] == next_path[res]) {
if (d & 2) {
// horizontal movement
assert(delta.x[d] == 0);
assert(abs(delta.y[d]) == 1);
int wall_y = min(py, py + delta.y[d]);
edge_wall_hit_count_horizontal[px + delta.x[d]][wall_y]++;
}
else {
// vertical movement
assert(abs(delta.x[d]) == 1);
assert(delta.y[d] == 0);
int wall_x = min(px, px + delta.x[d]);
edge_wall_hit_count_vertical[wall_x][py + delta.y[d]]++;
}
}
}
}
}
}
int main(int argc, char *argv[]) {
cin.tie(0);
ios::sync_with_stdio(false);
receive_first_input();
init();
solve();
return 0;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0