QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#135552#6394. Turn on the LightUrgantTeam#TL 0ms0kbC++235.4kb2023-08-05 17:52:532023-08-05 17:52:56

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-08-05 17:52:56]
  • 评测
  • 测评结果:TL
  • 用时:0ms
  • 内存:0kb
  • [2023-08-05 17:52:53]
  • 提交

answer

#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#define X first
#define Y second
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
using vi = vector<int>;
using ll = int64_t;
using vb = vector<bool>;
int prod(int a, int b, int p) {
	return ll(a) * b % p;
}
bool cpr(const int g, const int p) {
	int u = 1;
	for (int i = 1; i <= p - 2; ++i) {
		u = prod(u, g, p);
		if (u == 1) return false;
	}
	return true;
}
int pr(const int p) {
	for (int g = 2;; ++g)
		if (cpr(g, p))
			return g;
}
pair<vi, vi> logs(int p) {
	int g = pr(p);
	vi ans(p);
	vi powers(p - 1, 1);
	for (int i = 0, u = 1; i < p - 1; ++i) {
		ans[u] = i;
		powers[i] = u;
		u = prod(u, g, p);
	}
	return { ans, powers };
}
namespace FFT {
	using db = double;
	template<class T>
	struct Compl {
		T real, image;
		Compl(T r = 0, T i = 0) : real(r), image(i) {}
		Compl operator+(const Compl& c) const {
			return { real + c.real, image + c.image };
		}
		Compl operator-(const Compl& c) const {
			return { real - c.real, image - c.image };
		}
		Compl operator*(const Compl& c) const {
			return { real * c.real - image * c.image, image * c.real + c.image * real };
		}
		Compl operator/(const T& c) const {
			return { real / c, image / c };
		}
		Compl& operator=(const Compl& a) {
			real = a.real;
			image = a.image;
			return *this;
		}
		Compl& operator=(const db& a) {
			real = a;
			image = 0;
			return *this;
		}
	};
	using Complex = Compl<db>;
	struct FFT {
		const int n = 20;
		const int size = (1 << n);
		vector<Complex> root;
		vi revers;
		vector<Complex> fftA, fftB;
		FFT(int _n) : size(1 << _n), n(_n) {
			revers.resize(size), root.resize(size);
			fftA.resize(size); fftB.resize(size);
			for (int i = 0; i < size / 2; ++i) {
				root[i] = Complex(cos(2 * M_PI * i / size), sin(2 * M_PI * i / size));
				root[i + size / 2] = Complex(-root[i].real, -root[i].image);
			}
		}
		void fft(vector<Complex>& poly, int newN) {
			revers[0] = 0;
			for (int i = 1; i < 1 << newN; ++i) {
				if (i % 2 == 0) revers[i] = revers[i / 2] / 2;
				else revers[i] = revers[i / 2] / 2 + (1 << (newN - 1));
				if (revers[i] < i) swap(poly[revers[i]], poly[i]);
			}
			for (int level = 1; level <= newN; ++level)
				for(int block = 0; block < (1 << (newN - level)); ++block)
					for (int step = 0; step < (1 << (level - 1)); ++step) {
						int num1 = (block << level) + step;
						int num2 = num1 + (1 << level - 1);
						Complex valA = poly[num1];
						Complex valB = root[step << (n - level)] * poly[num2];
						poly[num1] = valA + valB;
						poly[num2] = valA - valB;
					}
		}
		void rev_fft(vector<Complex>& poly, int step) {
			fft(poly, step);
			reverse(poly.begin(), poly.begin() + (1 << step));
			for (int i = 0; i < (1 << step); ++i) poly[i] = poly[i] / (1 << step);
		}
		vector<db> multiply(const vector<db>& A, const vector<db>& B, int step) {
			fill(fftA.begin(), fftA.begin() + (1 << step), 0.);
			fill(fftB.begin(), fftB.begin() + (1 << step), 0.);
			copy(A.begin(), A.end(), fftA.begin());
			copy(B.begin(), B.end(), fftB.begin());
			fft(fftA, step); fft(fftB, step);
			for (int i = 0; i < (1 << step); ++i)
				fftA[i] = fftA[i] * fftB[i];
			rev_fft(fftA, step);
			vector<db> result(1 << step);
			for (int i = 0; i < (1 << step); ++i)
				result[i] = fftA[i].real;
			return result;
		}
	};

}
using vf = vector<double>;
int clo(int n) {
	for (int i = 31; i >= 0; --i)
		if (n & (1 << i)) return i;
}
vi check_occur(const vb& pattern, const vb& text) {
	static FFT::FFT fft(20);
	int P = pattern.size(), T = text.size();
	vf rpattern(P);
	for (int i = 0; i < P; ++i)
		rpattern[i] = pattern[P - 1 - i];
	vf txt(text.begin(), text.end());
	int expected_degree = txt.size() + rpattern.size() - 1;
	vf prd = fft.multiply(rpattern, txt, 1 + clo(expected_degree - 1));
	vi ans;
	int sum = 0;
	for (bool i : pattern)
		sum += i;
	for (int i = P - 1; i < T; ++i)
		if (prd[i] >= sum - .5)
			ans.push_back(i - P + 1);
	return ans;
}
int dif(int a, int b, int m) {
	if ((a -= b) < 0) a += m;
	return a;
}
pair<int, vi> find_ans(const vi& a, const int p) {
	auto it = find(a.begin(), a.end(), 0);
	if (it == a.end())
		return { 1, {0} };
	auto [l, pw] = logs(p);
	vb lgs(p - 1);
	for (int i : a)
		if (i)
			lgs[l[i]] = true;
	vb lgslgs = lgs;
	for (bool b : lgs) lgslgs.push_back(b);
	lgslgs.pop_back();
	int left = -1, right = a.size();
	vi best_incls;
	while (right - left >= 2) {
		int med = (left + right) / 2;
		vb pattern(p - 1);
		for (int i = 1; i <= med; ++i)
			pattern[l[i]] = true;
		vi incls = check_occur(pattern, lgslgs);
		if (incls.empty())
			right = med;
		else {
			left = med;
			best_incls.swap(incls);
		}
	}
	for (int& i : best_incls)
		i = pw[dif(0, i, p - 1)];
	sort(best_incls.begin(), best_incls.end());
	return {right, best_incls};
}
void solve_test() {
	int n, p;
	cin >> n >> p;
	vi a(n);
	for (int& i : a) cin >> i;
	pair<int, vi> ans = find_ans(a, p);
	cout << ans.Y.size() << ' ' << ans.X << '\n';
	for (int i = 0; i < ans.Y.size(); ++i)
		cout << ans.Y[i] << " \n"[i + 1 == ans.Y.size()];
}
void solve_tests() {
	int t;
	cin >> t;
	for (int i = 0; i < t; ++i)
		solve_test();
}
int main() {
#ifdef HOME
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	solve_tests();
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 0
Time Limit Exceeded

input:

3

output:


result: