QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#135552 | #6394. Turn on the Light | UrgantTeam# | TL | 0ms | 0kb | C++23 | 5.4kb | 2023-08-05 17:52:53 | 2023-08-05 17:52:56 |
Judging History
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