Submission #1172367


Source Code Expand

#include "bits/stdc++.h"
using namespace std;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
static const int INF = 0x3f3f3f3f; static const long long INFL = 0x3f3f3f3f3f3f3f3fLL;
typedef vector<int> vi; typedef pair<int, int> pii; typedef vector<pair<int, int> > vpii; typedef long long ll;
template<typename T, typename U> static void amin(T &x, U y) { if (y < x) x = y; }
template<typename T, typename U> static void amax(T &x, U y) { if (x < y) x = y; }

template<typename Arc>
struct StaticGraph {
	typedef pair<int, Arc> Edge;

	struct ArcList {
		ArcList() : arcBegin(), arcEnd() {}
		ArcList(const Arc *arcBegin, const Arc *arcEnd) : arcBegin(arcBegin), arcEnd(arcEnd) {}

		const Arc *begin() const { return arcBegin; }
		const Arc *end() const { return arcEnd; }
		int size() const { return (int)(arcEnd - arcBegin); }
		bool empty() const { return arcBegin == arcEnd; }
		Arc operator[](int i) const { return arcBegin[i]; }

	private:
		const Arc * const arcBegin, * const arcEnd;
	};

	int size() const { return (int)offsets.size() - 1; }

	ArcList operator[](int i) const {
		return ArcList(arcs.data() + offsets[i], arcs.data() + offsets[i + 1]);
	}

	void init(int n, const vector<Edge> &edges) {
		int m = (int)edges.size();
		arcs.resize(m + 1);
		offsets.assign(n + 1, 0);
		for (int ei = 0; ei < m; ++ ei)
			++ offsets[edges[ei].first];
		for (int i = 0; i < n; ++ i)
			offsets[i + 1] += offsets[i];
		for (int ei = m - 1; ei >= 0; -- ei)
			arcs[-- offsets[edges[ei].first]] = edges[ei].second;
	}


	vector<Arc> arcs;
	vector<int> offsets;
};

struct Food {
	int F;
	int D;
	Food() : F(0), D(0) {}

	int getTrueScoreAt(int t) const {
		return F - D * t;
	}

	bool exists() const {
		return F != 0 || D != 0;
	}
};

const int MaxV = 2500;
array<uint64_t, MaxV> hashKeys;
struct State {
	double perturbatedScore;
	int trueScore;
	bitset<MaxV> visited;
	int currentVertex;
	shared_ptr<State> parent;
	uint64_t hash;
	State() {}
	explicit State(int startVertex) :
		perturbatedScore(0), trueScore(0), currentVertex(startVertex),
		hash(startVertex) {
	}
	State(const shared_ptr<State> &s, int newVertex) :
		perturbatedScore(s->perturbatedScore), trueScore(s->trueScore), visited(s->visited), currentVertex(newVertex),
		parent(s), hash(s->hash - s->currentVertex + newVertex) {
	}

	void visit(int u) {
		assert(!visited[u]);
		visited[u] = true;
		hash += hashKeys[u];
	}

	uint64_t getHash() const {
		return hash;
	}
};


int main() {
#if defined(MY_LOCAL_RUN) && 1
	freopen("C:/test/sagyo/B-in-1.txt", "r", stdin);
	freopen("C:/test/sagyo/B-out.txt", "w", stdout);
#endif
	{
		mt19937_64 re;
		rep(i, MaxV)
			hashKeys[i] = re();
	}
	chrono::high_resolution_clock clk;
	int H; int W; int K;
	while (~scanf("%d%d%d", &H, &W, &K)) {
		auto startTime = clk.now();
		int startY; int startX;
		scanf("%d%d", &startY, &startX), -- startY, -- startX;
		vector<bool> blocked(H * W);
		rep(i, H) {
			char buf[101];
			scanf("%s", buf);
			rep(j, W)
				blocked[i * W + j] = buf[j] == '#';
		}
		StaticGraph<int> graph;
		{
			vector<StaticGraph<int>::Edge> edges;
			rep(i, H) rep(j, W) if (!blocked[i * W + j]) {
				static const int dy[4] = { 0, 1, 0, -1 }, dx[4] = { 1, 0, -1, 0 };
				for (int d = 0; d < 4; ++ d) {
					int yy = i + dy[d], xx = j + dx[d];
					if (yy < 0 || yy >= H || xx < 0 || xx >= W) continue;
					if (blocked[yy * W + xx]) continue;
					edges.emplace_back(i * W + j, yy * W + xx);
				}
			}
			graph.init(H * W, edges);
		}
		int N;
		scanf("%d", &N);
		vector<Food> foods(H * W, Food());
		rep(i, N) {
			int y; int x; int F; int D;
			scanf("%d%d%d%d", &y, &x, &F, &D), -- y, -- x;
			Food &f = foods[y * W + x];
			f.F += F;
			f.D += D;
		}

		auto getMoves = [W, K](const State &state) {
			vector<int> path;
			for (const State *s = &state; ; s = s->parent.get()) {
				path.push_back(s->currentVertex);
				if (!s->parent) break;
			}
			reverse(path.begin(), path.end());
			assert(!path.empty() && path.size() <= (size_t)K + 1);
			int lastVertex = path.back();
			path.resize(K + 1, lastVertex);
			string moves;
			rep(k, K) {
				int u = path[k], v = path[k + 1];
				if (u == v) {
					moves += '-';
					continue;
				}
				int i = u / W, j = u % W;
				static const int dy[4] = { 0, 1, 0, -1 }, dx[4] = { 1, 0, -1, 0 };
				for (int d = 0; d < 4; ++ d) {
					int yy = i + dy[d], xx = j + dx[d];
					if (yy * W + xx == v)
						moves += "RDLU"[d];
				}
			}
			assert(moves.size() == K);
			return moves;
		};
		int bestMoveScore = 0;
		string bestMoves;
		mt19937 re;
		for (int iter = 0; ; ++ iter) {
			if (chrono::duration_cast<chrono::milliseconds>(clk.now() - startTime).count() > 9000)
				break;
			vector<double> randomMultiplier(H * W, 1);
			{
				normal_distribution<double> dist(1.0, 0.05);
				rep(i, H * W) if (foods[i].exists())
					randomMultiplier[i] = dist(re);
			}
			const int beamSize = 100;
			vector<shared_ptr<State>> que;
			vector<State> nque;
			unordered_map<uint64_t, double> hashMap;
			State bestState(startY * W + startX);
			hashMap[bestState.getHash()] = 0;
			nque.push_back(bestState);
			double prevMaxScore = 0;
			int lastMaxScoreT = 0;
			for (int t = 0; t <= K; ++ t) {
				if (nque.empty()) break;
				{
					double maxScore = -INF;
					for (auto &&s : nque)
						amax(maxScore, s.perturbatedScore);
					//cerr << t << ": " << maxScore << endl;
					if (prevMaxScore >= maxScore) {
						if (t - lastMaxScoreT >= 50)
							break;
					} else {
						lastMaxScoreT = t;
					}
					prevMaxScore = maxScore;
				}
				if (nque.size() > (size_t)beamSize) {
					double coeff = max(1., t * 1. / 100);
					auto getScore = [t, coeff](const State &a) -> double {
						return a.perturbatedScore * coeff + a.trueScore * (1 - coeff);
					};
					nth_element(nque.begin(), nque.begin() + beamSize, nque.end(),
						[getScore](const State &a, const State &b) {
						return getScore(a) > getScore(b);
					});
					nque.resize(beamSize);
				}
				que.clear();
				for (auto &&s : nque) {
					if (hashMap[s.getHash()] == s.trueScore)
						que.push_back(make_shared<State>(s));
				}
				nque.clear();
				for (auto &&state : que) {
					for (int newVertex : graph[state->currentVertex]) {
						State newState(state, newVertex);
						if (!state->visited[newVertex] && foods[newVertex].exists()) {
							newState.visit(newVertex);
							int score = foods[newVertex].getTrueScoreAt(t);
							newState.trueScore += score;
							newState.perturbatedScore += score * randomMultiplier[newVertex];
						}
						if (bestState.trueScore < newState.trueScore)
							bestState = newState;
						{
							auto it = hashMap.emplace(make_pair(newState.getHash(), -INF)).first;
							if (newState.trueScore <= it->second)
								continue;
							it->second = newState.trueScore;
						}
						nque.push_back(std::move(newState));
					}
				}
			}
#ifdef MY_LOCAL_RUN
			cerr << iter << ": " << bestState.trueScore << endl;
			//cerr << getMoves(bestState).substr(0, 200) << endl;
#endif
			if (bestMoveScore < bestState.trueScore) {
				bestMoveScore = bestState.trueScore;
				bestMoves = getMoves(bestState);
			}
		}
#ifdef MY_LOCAL_RUN
		cerr << "best: " << bestMoveScore << endl;
#endif
		puts(bestMoves.c_str());
	}
	return 0;
}

Submission Info

Submission Time
Task B - Food Collector
User anta
Language C++14 (GCC 5.4.1)
Score 20378
Code Size 7623 Byte
Status AC
Exec Time 9088 ms
Memory 18632 KB

Compile Error

./Main.cpp: In function ‘int main()’:
./Main.cpp:112:56: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d%d", &startY, &startX), -- startY, -- startX;
                                                        ^
./Main.cpp:116:20: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
    scanf("%s", buf);
                    ^
./Main.cpp:135:18: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d", &N);
                  ^
./Main.cpp:139:49: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
    scanf("%d%d%d%d", &y, &x, &F, &D), -- y, -- x;
                                                 ^

Judge Result

Set Name test_01 test_02 test_03 test_04 test_05 test_06 test_07 test_08 test_09 test_10
Score / Max Score 1956 / 20000 2784 / 20000 2133 / 20000 1167 / 20000 2093 / 20000 2608 / 20000 2205 / 20000 1729 / 20000 1239 / 20000 2464 / 20000
Status
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
Set Name Test Cases
test_01 subtask_01_01.txt
test_02 subtask_01_02.txt
test_03 subtask_01_03.txt
test_04 subtask_01_04.txt
test_05 subtask_01_05.txt
test_06 subtask_01_06.txt
test_07 subtask_01_07.txt
test_08 subtask_01_08.txt
test_09 subtask_01_09.txt
test_10 subtask_01_10.txt
Case Name Status Exec Time Memory
subtask_01_01.txt AC 9004 ms 13924 KB
subtask_01_02.txt AC 9088 ms 18632 KB
subtask_01_03.txt AC 9022 ms 17280 KB
subtask_01_04.txt AC 9034 ms 11120 KB
subtask_01_05.txt AC 9021 ms 17024 KB
subtask_01_06.txt AC 9003 ms 18048 KB
subtask_01_07.txt AC 9062 ms 17172 KB
subtask_01_08.txt AC 9050 ms 15832 KB
subtask_01_09.txt AC 9034 ms 8828 KB
subtask_01_10.txt AC 9011 ms 18048 KB