QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#135643 | #6399. Classic: Classical Problem | UrgantTeam# | WA | 1ms | 3868kb | C++23 | 7.4kb | 2023-08-05 20:02:24 | 2023-08-05 20:02:27 |
Judging History
answer
#pragma GCC optimize("Ofast,unroll-loops")
#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 = float;
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() + 1, 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<float>;
int clo(int n) {
for (int i = 31; i >= 0; --i)
if (n & (1 << i)) return i;
}
pair<int, vi> check_occur_naive(const vb& pattern, const vb& text, const int sum) {
vi pi;
int P = pattern.size(), T = text.size();
for (int i = 0; i < P; ++i)
if (pattern[i]) pi.push_back(i);
int lans = 0;
vi ans;
for (int i = 0; i < T - P + 1; ++i) {
int cans = 0;
for (int j : pi)
if (text[i + j])
++cans;
lans = max(lans, cans);
if (cans >= sum)
ans.push_back(i);
}
return { lans, ans };
}
pair<int, vi> check_occur(const vb& pattern, const vb& text) {
int sum = 0;
for (bool i : pattern)
sum += i;
if (sum <= 200) return check_occur_naive(pattern, text, sum);
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 lans = 0;
for (int i = P - 1; i < T; ++i) {
int prdint = prd[i] + .5;
if (prdint >= sum)
ans.push_back(i - P + 1);
lans = max(lans, prdint);
}
return { lans, ans };
}
int dif(int a, int b, int m) {
if ((a -= b) < 0) a += m;
return a;
}
int summ(int a, int b, int m) {
if ((a += b) >= m) 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} };
if (a.size() == 1) {
vi a(p);
for (int i = 1; i < p; ++i)
a[i] = i;
return { 1, a };
}
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;
cerr << "[" << left << "; " << right << "] -> med;\n";
vb pattern(p - 1);
for (int i = 1; i <= med; ++i)
pattern[l[i]] = true;
auto [lans, incls] = check_occur(pattern, lgslgs);
if (incls.empty())
right = lans + 1;
else {
int actual_ans = med;
for (int i : best_incls) {
if (actual_ans > med)
break;
for (; actual_ans < p - 1; ++actual_ans)
if (!lgslgs[i + l[actual_ans + 1]])
break;
}
left = actual_ans;
if (med == actual_ans)
best_incls.swap(incls);
else
best_incls.clear();
}
}
if (best_incls.empty()) {
vb pattern(p - 1);
for (int i = 1; i <= left; ++i)
pattern[l[i]] = true;
best_incls = check_occur(pattern, lgslgs).Y;
}
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() {
cerr << "Began!\n";
int t;
cin >> t;
for (int i = 0; i < t; ++i)
solve_test();
cerr << "Finished!\n";
}
#include <random>
#include <fstream>
#include <chrono>
using namespace std;
void generate_test() {
int p = 199999;
int m = 140000;
ofstream fout("input.txt");
fout << 1 << '\n' << m << ' ' << p << '\n';
fout << 0;
vi v(p - 1);
for (int i = 1; i < p; ++i) v[i - 1] = i;
mt19937 rng;
shuffle(v.begin(), v.end(), rng);
for (int i = 0; i < m - 1; ++i)
fout << ' ' << v[i];
fout << '\n';
}
int main() {
#ifdef HOME
//generate_test();
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios_base::sync_with_stdio(0); cin.tie(0);
auto start_time = chrono::high_resolution_clock::now();
solve_tests();
auto end_time = chrono::high_resolution_clock::now();
cerr << "Spent: " << (end_time - start_time) / 1.ms << " ms\n";
}
詳細信息
Test #1:
score: 0
Wrong Answer
time: 1ms
memory: 3868kb
input:
3 2 3 0 2 3 5 2 3 4 3 5 0 2 3
output:
0 2 1 1 0 2 2 2 3
result:
wrong answer 1st lines differ - expected: '1 2', found: '0 2'