結果

問題 No.408 五輪ピック
ユーザー antaanta
提出日時 2017-05-07 15:00:27
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 91 ms / 5,000 ms
コード長 4,571 bytes
コンパイル時間 1,632 ms
コンパイル使用メモリ 177,084 KB
実行使用メモリ 6,132 KB
最終ジャッジ日時 2023-10-12 16:03:39
合計ジャッジ時間 4,032 ms
ジャッジサーバーID
(参考情報)
judge11 / judge12
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,348 KB
testcase_01 AC 2 ms
4,348 KB
testcase_02 AC 2 ms
4,352 KB
testcase_03 AC 2 ms
4,348 KB
testcase_04 AC 2 ms
4,348 KB
testcase_05 AC 58 ms
4,700 KB
testcase_06 AC 33 ms
5,156 KB
testcase_07 AC 39 ms
5,360 KB
testcase_08 AC 40 ms
4,432 KB
testcase_09 AC 38 ms
4,468 KB
testcase_10 AC 28 ms
4,904 KB
testcase_11 AC 26 ms
4,624 KB
testcase_12 AC 42 ms
5,168 KB
testcase_13 AC 55 ms
4,348 KB
testcase_14 AC 12 ms
4,348 KB
testcase_15 AC 65 ms
4,644 KB
testcase_16 AC 60 ms
4,524 KB
testcase_17 AC 54 ms
4,836 KB
testcase_18 AC 53 ms
5,016 KB
testcase_19 AC 51 ms
5,452 KB
testcase_20 AC 18 ms
4,476 KB
testcase_21 AC 11 ms
4,352 KB
testcase_22 AC 31 ms
5,248 KB
testcase_23 AC 91 ms
5,912 KB
testcase_24 AC 68 ms
5,500 KB
testcase_25 AC 58 ms
4,844 KB
testcase_26 AC 53 ms
6,132 KB
testcase_27 AC 60 ms
4,652 KB
testcase_28 AC 51 ms
4,612 KB
testcase_29 AC 51 ms
4,708 KB
testcase_30 AC 2 ms
4,348 KB
testcase_31 AC 2 ms
4,348 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#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; }

struct GFLookup {
	static const int Deg = 16;
	using Word = uint16_t;
	enum : uint32_t {
		Poly = 0x1002d,
		Mask = 0x10000,
		Order = 0xffff,
	};

	array<Word, 1 << Deg> pow, log;

	GFLookup() {
		uint32_t a = 1;
		for (uint32_t i = 0; i < Order; ++ i) {
			pow[i] = (Word)a;
			log[a] = (Word)i;
			a <<= 1;
			if (a & Mask) a ^= Poly;
		}
	}

	Word mul(Word x, Word y) const {
		if (x == 0 || y == 0)
			return 0;
		uint32_t k = (uint32_t)log[x] + log[y];
		if (k >= Order) k -= Order;
		return pow[k];
	}
};


int main() {
	random_device rd;
	using F = uint16_t;
	auto random = [&rd]() {
		return uint16_t(rd() & (GFLookup::Mask - 1));
	};
	struct Edge {
		int u, v;
		F value;
	};
	GFLookup gf;
	const int K = 4;
	//See: "Parameterized Algorithms" Ch.10.4.1
	auto solve = [&gf, K](int N, const vector<Edge> &edges, const vector<vector<F>> &y) {
		F totalSum = 0;
		vector<F> ySum(N);
		vector<vector<F>> dp;
		rep(X, 1 << K) {
			rep(i, N) {
				F sum = 0;
				rep(k, K) if (X >> k & 1)
					sum ^= y[i][k];
				ySum[i] = sum;
			}
			dp.assign(K, vector<F>(N));
			for (const Edge &e : edges) if(e.u == 0 && e.v != 0)
				dp[0][e.v] ^= gf.mul(e.value, ySum[e.v]);
			rep(k, K - 1) {
				for (const Edge &e : edges) if (e.v != 0) {
					F x = dp[k][e.u];
					if (x != 0)
						dp[k + 1][e.v] ^= gf.mul(gf.mul(x, e.value), ySum[e.v]);
				}
			}
			for (const Edge &e : edges) if (e.v == 0)
				totalSum ^= gf.mul(dp[K - 1][e.u], e.value);
		}
		return totalSum != 0;
	};
	int N; int M;
	while (~scanf("%d%d", &N, &M)) {
		vector<Edge> edges(M * 2);
		for (int i = 0; i < M; ++ i) {
			int u, v;
			scanf("%d%d", &u, &v), -- u, -- v;
			edges[i * 2 + 0] = { u, v, random() };
			edges[i * 2 + 1] = { v, u, random() };
		}
		vector<vector<F>> y(N, vector<F>(K));
		rep(i, N) rep(k, K)
			y[i][k] = random();
		bool ans = solve(N, edges, y);
		if (!ans) {
			puts("NO");
			continue;
		}
		puts("YES");
#if 0
		//実際の解の構成
		//"Fast Witness Extraction Using a Decision Oracle" <https://arxiv.org/abs/1508.03572>
		vector<int> U(edges.size());
		vector<bool> tmpVis(edges.size());
		vector<Edge> tmpEdges;
		vector<int> id(N, -1);
		auto checkAndCut = [random, solve, K, &id, &edges, &U, &tmpVis, &tmpEdges](const vector<int> &A) {
			for (int i : A) tmpVis[i] = true;
			int N = 0;
			id[0] = N ++;
			for (int i : U) if (!tmpVis[i]) {
				const Edge &e = edges[i];
				if (id[e.u] == -1) id[e.u] = N ++;
				if (id[e.v] == -1) id[e.v] = N ++;
				tmpEdges.push_back(Edge{ id[e.u], id[e.v], random() });
			}
			vector<vector<F>> y(N, vector<F>(K));
			rep(i, N) rep(k, K)
				y[i][k] = random();
			bool result = solve(N, tmpEdges, y);
			for (int i : U) if (!tmpVis[i]) {
				const Edge &e = edges[i];
				id[e.u] = id[e.v] = -1;
			}
			id[0] = -1;
			if (result)
				U.erase(remove_if(U.begin(), U.end(), [&](int i) { return tmpVis[i]; }), U.end());
			for (int i : A) tmpVis[i] = false;
			tmpEdges.clear();
			return result;
		};
		iota(U.begin(), U.end(), 0);
		vector<int> W;
		queue<vector<int>> Q;
		Q.push(U);
		while (!Q.empty()) {
			vector<int> A = Q.front();
			Q.pop();
			if (A.size() == 1) {
				W.push_back(A[0]);
				continue;
			}
			vector<int> A1(A.begin(), A.begin() + A.size() / 2);
			vector<int> A2(A.begin() + A.size() / 2, A.end());
			if (checkAndCut(A1)) {
				Q.push(A2);
			} else if(checkAndCut(A2)) {
				Q.push(A1);
			} else {
				Q.push(A1);
				Q.push(A2);
			}
		}
		U = W;
		while ((int)W.size() > K + 1) {
			if (checkAndCut(vector<int>{W.back()}))
				W.pop_back();
			else
				rotate(W.begin(), W.begin() + 1, W.end());
		}
		assert(W.size() == K + 1);
		vector<int> next(N, -1);
		for (int i : W) {
			auto e = edges[i];
			assert(next[e.u] == -1);
			next[e.u] = e.v;
		}
		vector<int> cycle = { 0 };
		{
			int u = 0;
			rep(k, K) {
				u = next[u];
				cycle.push_back(u);
				assert(u != -1);
			}
			assert(next[u] == 0);
		}
		/*
		for (int u : cycle)
			cerr << u + 1 << ' ';
		cerr << endl;
		*/
#endif
	}
	return 0;
}
0