QOJ.ac
QOJ
The 2nd Universal Cup Finals is coming! Check out our event page, schedule, and competition rules!
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#273723 | #7876. Cyclic Substrings | ucup-team1055# | AC ✓ | 1992ms | 580588kb | C++20 | 32.6kb | 2023-12-03 03:35:40 | 2023-12-03 03:35:41 |
Judging History
answer
#line 2 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"
using namespace std;
#include<bits/stdc++.h>
#line 1 "/Users/noya2/Desktop/Noya2_library/template/inout_old.hpp"
namespace noya2 {
template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
os << p.first << " " << p.second;
return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
is >> p.first >> p.second;
return is;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
int s = (int)v.size();
for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
for (auto &x : v) is >> x;
return is;
}
void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
cin >> t;
in(u...);
}
void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
cout << t;
if (sizeof...(u)) cout << sep;
out(u...);
}
template<typename T>
void out(const vector<vector<T>> &vv){
int s = (int)vv.size();
for (int i = 0; i < s; i++) out(vv[i]);
}
struct IoSetup {
IoSetup(){
cin.tie(nullptr);
ios::sync_with_stdio(false);
cout << fixed << setprecision(15);
cerr << fixed << setprecision(7);
}
} iosetup_noya2;
} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/const.hpp"
namespace noya2{
const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 = 998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";
void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }
} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/utils.hpp"
namespace noya2{
unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
if (a == 0 || b == 0) return a + b;
int n = __builtin_ctzll(a); a >>= n;
int m = __builtin_ctzll(b); b >>= m;
while (a != b) {
int mm = __builtin_ctzll(a - b);
bool f = a > b;
unsigned long long c = f ? a : b;
b = f ? b : a;
a = (c - b) >> mm;
}
return a << min(n, m);
}
template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }
long long sqrt_fast(long long n) {
if (n <= 0) return 0;
long long x = sqrt(n);
while ((x + 1) * (x + 1) <= n) x++;
while (x * x > n) x--;
return x;
}
template<typename T> T floor_div(const T n, const T d) {
assert(d != 0);
return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}
template<typename T> T ceil_div(const T n, const T d) {
assert(d != 0);
return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}
template<typename T> void uniq(vector<T> &v){
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
}
template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }
template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }
template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }
} // namespace noya2
#line 8 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"
#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;
namespace noya2{
/* ~ (. _________ . /) */
}
using namespace noya2;
#line 2 "c.cpp"
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#line 2 "/Users/noya2/Desktop/Noya2_library/string/rolling_hash.hpp"
#line 4 "/Users/noya2/Desktop/Noya2_library/string/rolling_hash.hpp"
namespace noya2{
struct RollingHash {
using ull = unsigned long long;
RollingHash(const string &s = ""){ build(s);}
ull get(int l, int r){
assert(0 <= l && l <= r && r <= n);
return cal_mod(inner_hash[r] + POSITIVISER - mul_mod(inner_hash[l], pow_base[r-l]));
}
static ull get_hash(const string &s){
int len = s.size();
set_hash();
extend_pow_base(len);
ull res = 0;
for (int i = 0; i < len; i++) res = cal_mod(mul_mod(res,BASE) + s[i]);
return res;
}
size_t size() const { return n; }
template<class... Hash_Lengths> static ull concat(const Hash_Lengths&... hash_length){
return inner_concat(0ULL,hash_length...);
}
private:
static ull inner_concat(const ull& temp){
return temp;
}
template<class... Tail> static ull inner_concat(const ull& temp, const ull& hash, const int& len, const Tail&... tail){
return inner_concat(cal_mod(cal_mod(mul_mod(temp,pow_base[len]))+hash),tail...);
}
static constexpr ull MASK30 = (1ULL << 30) - 1;
static constexpr ull MASK31 = (1ULL << 31) - 1;
static constexpr ull MASK61 = (1ULL << 61) - 1;
static constexpr ull MOD = (1ULL << 61) - 1;
static constexpr ull POSITIVISER = MOD * 4;
static ull BASE;
static vector<ull> pow_base;
static ull mul_mod(ull a, ull b){
ull au = a >> 31, ad = a & MASK31;
ull bu = b >> 31, bd = b & MASK31;
ull mid = ad * bu + au * bd;
ull midu = mid >> 30, midd = mid & MASK30;
return (au * bu * 2 + midu + (midd << 31) + ad * bd);
}
static ull cal_mod(ull x){
ull xu = x >> 61;
ull xd = x & MASK61;
ull res = xu + xd;
if (res >= MOD) res -= MOD;
return res;
}
static void set_hash(){
if (BASE == 0) BASE = (1UL<<31) + (random_device()() & MASK31);
}
static void extend_pow_base(int len){
int nlen = pow_base.size();
if (nlen > len) return ;
pow_base.resize(len+1);
for (int i = nlen; i <= len; i++){
pow_base[i] = cal_mod(mul_mod(pow_base[i-1],BASE));
}
}
string str;
int n;
vector<ull> inner_hash;
void build(const string &s){
set_hash();
str = s;
n = s.size();
extend_pow_base(n);
inner_hash.resize(n+1);
inner_hash[0] = 0;
for (int i = 0; i < n; i++) inner_hash[i+1] = cal_mod(mul_mod(inner_hash[i],BASE) + s[i]);
}
};
using ull = unsigned long long;
ull RollingHash::BASE = 0;
vector<ull> RollingHash::pow_base = vector<ull>(1,1);
using roriha = RollingHash;
} // namespace noya2
#line 7 "c.cpp"
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
vector<int> manacher(string &s){ // ans[i] : maximum radius of palindrome centered at s[i]
int n = s.size();
vector<int> ans(n,0);
int i = 0, len = 0;
while (i < n){
while (i - len >= 0 && i + len < n && s[i-len] == s[i+len]) len++;
ans[i] = len;
int k = 1;
while (i - k >= 0 && k + ans[i-k] < len) ans[i+k] = ans[i-k], k++;
i += k, len -= k;
}
return ans;
}
vector<int> palindrome_length(string s){ // ans[i] : maximum length of palindrome centered at (i % 2 == 0 ? s[i/2] : s[i/2]|s[i/2+1])
string t = "$";
for (char c : s) t += c, t += '$';
vector<int> a = manacher(t);
vector<int> ans(a.size()-2);
for (int i = 0; i < (int)a.size()-2; i++) ans[i] = a[i+1]-1;
return ans;
}
namespace atcoder {
namespace internal {
std::vector<int> sa_naive(const std::vector<int>& s) {
int n = int(s.size());
std::vector<int> sa(n);
std::iota(sa.begin(), sa.end(), 0);
std::sort(sa.begin(), sa.end(), [&](int l, int r) {
if (l == r) return false;
while (l < n && r < n) {
if (s[l] != s[r]) return s[l] < s[r];
l++;
r++;
}
return l == n;
});
return sa;
}
std::vector<int> sa_doubling(const std::vector<int>& s) {
int n = int(s.size());
std::vector<int> sa(n), rnk = s, tmp(n);
std::iota(sa.begin(), sa.end(), 0);
for (int k = 1; k < n; k *= 2) {
auto cmp = [&](int x, int y) {
if (rnk[x] != rnk[y]) return rnk[x] < rnk[y];
int rx = x + k < n ? rnk[x + k] : -1;
int ry = y + k < n ? rnk[y + k] : -1;
return rx < ry;
};
std::sort(sa.begin(), sa.end(), cmp);
tmp[sa[0]] = 0;
for (int i = 1; i < n; i++) {
tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0);
}
std::swap(tmp, rnk);
}
return sa;
}
// SA-IS, linear-time suffix array construction
// Reference:
// G. Nong, S. Zhang, and W. H. Chan,
// Two Efficient Algorithms for Linear Time Suffix Array Construction
template <int THRESHOLD_NAIVE = 10, int THRESHOLD_DOUBLING = 40>
std::vector<int> sa_is(const std::vector<int>& s, int upper) {
int n = int(s.size());
if (n == 0) return {};
if (n == 1) return {0};
if (n == 2) {
if (s[0] < s[1]) {
return {0, 1};
} else {
return {1, 0};
}
}
if (n < THRESHOLD_NAIVE) {
return sa_naive(s);
}
if (n < THRESHOLD_DOUBLING) {
return sa_doubling(s);
}
std::vector<int> sa(n);
std::vector<bool> ls(n);
for (int i = n - 2; i >= 0; i--) {
ls[i] = (s[i] == s[i + 1]) ? ls[i + 1] : (s[i] < s[i + 1]);
}
std::vector<int> sum_l(upper + 1), sum_s(upper + 1);
for (int i = 0; i < n; i++) {
if (!ls[i]) {
sum_s[s[i]]++;
} else {
sum_l[s[i] + 1]++;
}
}
for (int i = 0; i <= upper; i++) {
sum_s[i] += sum_l[i];
if (i < upper) sum_l[i + 1] += sum_s[i];
}
auto induce = [&](const std::vector<int>& lms) {
std::fill(sa.begin(), sa.end(), -1);
std::vector<int> buf(upper + 1);
std::copy(sum_s.begin(), sum_s.end(), buf.begin());
for (auto d : lms) {
if (d == n) continue;
sa[buf[s[d]]++] = d;
}
std::copy(sum_l.begin(), sum_l.end(), buf.begin());
sa[buf[s[n - 1]]++] = n - 1;
for (int i = 0; i < n; i++) {
int v = sa[i];
if (v >= 1 && !ls[v - 1]) {
sa[buf[s[v - 1]]++] = v - 1;
}
}
std::copy(sum_l.begin(), sum_l.end(), buf.begin());
for (int i = n - 1; i >= 0; i--) {
int v = sa[i];
if (v >= 1 && ls[v - 1]) {
sa[--buf[s[v - 1] + 1]] = v - 1;
}
}
};
std::vector<int> lms_map(n + 1, -1);
int m = 0;
for (int i = 1; i < n; i++) {
if (!ls[i - 1] && ls[i]) {
lms_map[i] = m++;
}
}
std::vector<int> lms;
lms.reserve(m);
for (int i = 1; i < n; i++) {
if (!ls[i - 1] && ls[i]) {
lms.push_back(i);
}
}
induce(lms);
if (m) {
std::vector<int> sorted_lms;
sorted_lms.reserve(m);
for (int v : sa) {
if (lms_map[v] != -1) sorted_lms.push_back(v);
}
std::vector<int> rec_s(m);
int rec_upper = 0;
rec_s[lms_map[sorted_lms[0]]] = 0;
for (int i = 1; i < m; i++) {
int l = sorted_lms[i - 1], r = sorted_lms[i];
int end_l = (lms_map[l] + 1 < m) ? lms[lms_map[l] + 1] : n;
int end_r = (lms_map[r] + 1 < m) ? lms[lms_map[r] + 1] : n;
bool same = true;
if (end_l - l != end_r - r) {
same = false;
} else {
while (l < end_l) {
if (s[l] != s[r]) {
break;
}
l++;
r++;
}
if (l == n || s[l] != s[r]) same = false;
}
if (!same) rec_upper++;
rec_s[lms_map[sorted_lms[i]]] = rec_upper;
}
auto rec_sa =
sa_is<THRESHOLD_NAIVE, THRESHOLD_DOUBLING>(rec_s, rec_upper);
for (int i = 0; i < m; i++) {
sorted_lms[i] = lms[rec_sa[i]];
}
induce(sorted_lms);
}
return sa;
}
} // namespace internal
std::vector<int> suffix_array(const std::vector<int>& s, int upper) {
assert(0 <= upper);
for (int d : s) {
assert(0 <= d && d <= upper);
}
auto sa = internal::sa_is(s, upper);
return sa;
}
template <class T> std::vector<int> suffix_array(const std::vector<T>& s) {
int n = int(s.size());
std::vector<int> idx(n);
iota(idx.begin(), idx.end(), 0);
sort(idx.begin(), idx.end(), [&](int l, int r) { return s[l] < s[r]; });
std::vector<int> s2(n);
int now = 0;
for (int i = 0; i < n; i++) {
if (i && s[idx[i - 1]] != s[idx[i]]) now++;
s2[idx[i]] = now;
}
return internal::sa_is(s2, now);
}
std::vector<int> suffix_array(const std::string& s) {
int n = int(s.size());
std::vector<int> s2(n);
for (int i = 0; i < n; i++) {
s2[i] = s[i];
}
return internal::sa_is(s2, 255);
}
// Reference:
// T. Kasai, G. Lee, H. Arimura, S. Arikawa, and K. Park,
// Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its
// Applications
template <class T>
std::vector<int> lcp_array(const std::vector<T>& s,
const std::vector<int>& sa) {
int n = int(s.size());
assert(n >= 1);
std::vector<int> rnk(n);
for (int i = 0; i < n; i++) {
rnk[sa[i]] = i;
}
std::vector<int> lcp(n - 1);
int h = 0;
for (int i = 0; i < n; i++) {
if (h > 0) h--;
if (rnk[i] == 0) continue;
int j = sa[rnk[i] - 1];
for (; j + h < n && i + h < n; h++) {
if (s[j + h] != s[i + h]) break;
}
lcp[rnk[i] - 1] = h;
}
return lcp;
}
std::vector<int> lcp_array(const std::string& s, const std::vector<int>& sa) {
int n = int(s.size());
std::vector<int> s2(n);
for (int i = 0; i < n; i++) {
s2[i] = s[i];
}
return lcp_array(s2, sa);
}
// Reference:
// D. Gusfield,
// Algorithms on Strings, Trees, and Sequences: Computer Science and
// Computational Biology
template <class T> std::vector<int> z_algorithm(const std::vector<T>& s) {
int n = int(s.size());
if (n == 0) return {};
std::vector<int> z(n);
z[0] = 0;
for (int i = 1, j = 0; i < n; i++) {
int& k = z[i];
k = (j + z[j] <= i) ? 0 : std::min(j + z[j] - i, z[i - j]);
while (i + k < n && s[k] == s[i + k]) k++;
if (j + z[j] < i + z[i]) j = i;
}
z[0] = n;
return z;
}
std::vector<int> z_algorithm(const std::string& s) {
int n = int(s.size());
std::vector<int> s2(n);
for (int i = 0; i < n; i++) {
s2[i] = s[i];
}
return z_algorithm(s2);
}
} // namespace atcoder
namespace ebi {
template <class Monoid, Monoid (*op)(Monoid, Monoid), Monoid (*e)()>
struct DualSegtree {
public:
DualSegtree(int n_) : n(n_) {
size = 1;
while (size < n) size <<= 1;
data.assign(2 * size, e());
}
DualSegtree(const std::vector<Monoid> &vec) : n(vec.size()) {
size = 1;
while (size < n) size <<= 1;
data.assign(2 * size, e());
std::copy(vec.begin(), vec.end(), data.begin() + size);
}
Monoid get(int idx) const {
assert(0 <= idx && idx < n);
idx += size;
Monoid val = e();
while (idx > 0) {
val = op(val, data[idx]);
idx >>= 1;
}
return val;
}
void apply(int l, int r, Monoid x) {
assert(0 <= l && l <= r && r <= n);
l += size;
r += size;
while (l < r) {
if (l & 1) {
data[l] = op(data[l], x);
l++;
}
if (r & 1) {
r--;
data[r] = op(data[r], x);
}
l >>= 1;
r >>= 1;
}
return;
}
private:
std::vector<Monoid> data;
int n;
int size;
};
} // namespace ebi
int op(int a, int b){
return min(a,b);
}
int e(){
return iinf;
}
int mapping(int f, int x){
return min(f,x);
}
int composition(int f, int g){
return min(f,g);
}
int ideal(){
return iinf;
}
#line 2 "/Users/noya2/Desktop/Noya2_library/utility/modint.hpp"
#line 2 "/Users/noya2/Desktop/Noya2_library/math/prime.hpp"
#line 4 "/Users/noya2/Desktop/Noya2_library/math/prime.hpp"
namespace noya2 {
constexpr ll safe_mod(ll x, ll m) {
x %= m;
if (x < 0) x += m;
return x;
}
constexpr ll pow_mod_constexpr(ll x, ll n, int m) {
if (m == 1) return 0;
uint _m = (uint)(m);
ull r = 1;
ull y = safe_mod(x, m);
while (n) {
if (n & 1) r = (r * y) % _m;
y = (y * y) % _m;
n >>= 1;
}
return r;
}
constexpr bool is_prime_constexpr(int n) {
if (n <= 1) return false;
if (n == 2 || n == 7 || n == 61) return true;
if (n % 2 == 0) return false;
ll d = n - 1;
while (d % 2 == 0) d /= 2;
constexpr ll bases[3] = {2, 7, 61};
for (ll a : bases) {
ll t = d;
ll y = pow_mod_constexpr(a, t, n);
while (t != n - 1 && y != 1 && y != n - 1) {
y = y * y % n;
t <<= 1;
}
if (y != n - 1 && t % 2 == 0) {
return false;
}
}
return true;
}
template <int n> constexpr bool is_prime_flag = is_prime_constexpr(n);
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
a = safe_mod(a, b);
if (a == 0) return {b, 0};
long long s = b, t = a;
long long m0 = 0, m1 = 1;
while (t) {
long long u = s / t;
s -= t * u;
m0 -= m1 * u;
auto tmp = s;
s = t;
t = tmp;
tmp = m0;
m0 = m1;
m1 = tmp;
}
if (m0 < 0) m0 += b / s;
return {s, m0};
}
constexpr int primitive_root_constexpr(int m) {
if (m == 2) return 1;
if (m == 167772161) return 3;
if (m == 469762049) return 3;
if (m == 754974721) return 11;
if (m == 998244353) return 3;
int divs[20] = {};
divs[0] = 2;
int cnt = 1;
int x = (m - 1) / 2;
while (x % 2 == 0) x /= 2;
for (int i = 3; (ll)(i)*i <= x; i += 2) {
if (x % i == 0) {
divs[cnt++] = i;
while (x % i == 0) {
x /= i;
}
}
}
if (x > 1) {
divs[cnt++] = x;
}
for (int g = 2;; g++) {
bool ok = true;
for (int i = 0; i < cnt; i++) {
if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
ok = false;
break;
}
}
if (ok) return g;
}
}
template <int m> constexpr int primitive_root_flag = primitive_root_constexpr(m);
} // namespace noya2
#line 4 "/Users/noya2/Desktop/Noya2_library/utility/modint.hpp"
namespace noya2{
struct barrett {
uint _m;
ull im;
explicit barrett(uint m) : _m(m), im((ull)(-1) / m + 1) {}
uint umod() const { return _m; }
uint mul(uint a, uint b) const {
ull z = a;
z *= b;
ull x = ull((__uint128_t(z) * im) >> 64);
uint v = (uint)(z - x * _m);
if (_m <= v) v += _m;
return v;
}
};
template <int m>
struct static_modint {
using mint = static_modint;
public:
static constexpr int mod() { return m; }
static mint raw(int v) {
mint x;
x._v = v;
return x;
}
constexpr static_modint() : _v(0) {}
template<signed_integral T>
constexpr static_modint(T v){
ll x = (ll)(v % (ll)(umod()));
if (x < 0) x += umod();
_v = (uint)(x);
}
template<unsigned_integral T>
constexpr static_modint(T v){
_v = (uint)(v % umod());
}
constexpr unsigned int val() const { return _v; }
mint& operator++() {
_v++;
if (_v == umod()) _v = 0;
return *this;
}
mint& operator--() {
if (_v == 0) _v = umod();
_v--;
return *this;
}
mint operator++(int) {
mint result = *this;
++*this;
return result;
}
mint operator--(int) {
mint result = *this;
--*this;
return result;
}
constexpr mint& operator+=(const mint& rhs) {
_v += rhs._v;
if (_v >= umod()) _v -= umod();
return *this;
}
constexpr mint& operator-=(const mint& rhs) {
_v -= rhs._v;
if (_v >= umod()) _v += umod();
return *this;
}
constexpr mint& operator*=(const mint& rhs) {
ull z = _v;
z *= rhs._v;
_v = (uint)(z % umod());
return *this;
}
constexpr mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
constexpr mint operator+() const { return *this; }
constexpr mint operator-() const { return mint() - *this; }
constexpr mint pow(ll n) const {
assert(0 <= n);
mint x = *this, r = 1;
while (n) {
if (n & 1) r *= x;
x *= x;
n >>= 1;
}
return r;
}
constexpr mint inv() const {
if (prime) {
assert(_v);
return pow(umod() - 2);
} else {
auto eg = inv_gcd(_v, m);
assert(eg.first == 1);
return eg.second;
}
}
friend constexpr mint operator+(const mint& lhs, const mint& rhs) {
return mint(lhs) += rhs;
}
friend constexpr mint operator-(const mint& lhs, const mint& rhs) {
return mint(lhs) -= rhs;
}
friend constexpr mint operator*(const mint& lhs, const mint& rhs) {
return mint(lhs) *= rhs;
}
friend constexpr mint operator/(const mint& lhs, const mint& rhs) {
return mint(lhs) /= rhs;
}
friend constexpr bool operator==(const mint& lhs, const mint& rhs) {
return lhs._v == rhs._v;
}
friend constexpr bool operator!=(const mint& lhs, const mint& rhs) {
return lhs._v != rhs._v;
}
friend std::ostream &operator<<(std::ostream &os, const mint& p) {
return os << p.val();
}
friend std::istream &operator>>(std::istream &is, mint &a) {
long long t; is >> t;
a = mint(t);
return (is);
}
private:
unsigned int _v;
static constexpr unsigned int umod() { return m; }
static constexpr bool prime = is_prime_flag<m>;
};
template <int id> struct dynamic_modint {
using mint = dynamic_modint;
public:
static int mod() { return (int)(bt.umod()); }
static void set_mod(int m) {
assert(1 <= m);
bt = barrett(m);
}
static mint raw(int v) {
mint x;
x._v = v;
return x;
}
dynamic_modint() : _v(0) {}
template<signed_integral T>
dynamic_modint(T v){
ll x = (ll)(v % (ll)(mod()));
if (x < 0) x += mod();
_v = (uint)(x);
}
template<unsigned_integral T>
dynamic_modint(T v){
_v = (uint)(v % mod());
}
uint val() const { return _v; }
mint& operator++() {
_v++;
if (_v == umod()) _v = 0;
return *this;
}
mint& operator--() {
if (_v == 0) _v = umod();
_v--;
return *this;
}
mint operator++(int) {
mint result = *this;
++*this;
return result;
}
mint operator--(int) {
mint result = *this;
--*this;
return result;
}
mint& operator+=(const mint& rhs) {
_v += rhs._v;
if (_v >= umod()) _v -= umod();
return *this;
}
mint& operator-=(const mint& rhs) {
_v += mod() - rhs._v;
if (_v >= umod()) _v -= umod();
return *this;
}
mint& operator*=(const mint& rhs) {
_v = bt.mul(_v, rhs._v);
return *this;
}
mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
mint operator+() const { return *this; }
mint operator-() const { return mint() - *this; }
mint pow(long long n) const {
assert(0 <= n);
mint x = *this, r = 1;
while (n) {
if (n & 1) r *= x;
x *= x;
n >>= 1;
}
return r;
}
mint inv() const {
auto eg = noya2::inv_gcd(_v, mod());
assert(eg.first == 1);
return eg.second;
}
friend mint operator+(const mint& lhs, const mint& rhs) {
return mint(lhs) += rhs;
}
friend mint operator-(const mint& lhs, const mint& rhs) {
return mint(lhs) -= rhs;
}
friend mint operator*(const mint& lhs, const mint& rhs) {
return mint(lhs) *= rhs;
}
friend mint operator/(const mint& lhs, const mint& rhs) {
return mint(lhs) /= rhs;
}
friend bool operator==(const mint& lhs, const mint& rhs) {
return lhs._v == rhs._v;
}
friend bool operator!=(const mint& lhs, const mint& rhs) {
return lhs._v != rhs._v;
}
friend std::ostream &operator<<(std::ostream &os, const mint& p) {
return os << p.val();
}
friend std::istream &operator>>(std::istream &is, mint &a) {
long long t; is >> t;
a = mint(t);
return (is);
}
private:
unsigned int _v;
static barrett bt;
static unsigned int umod() { return bt.umod(); }
};
template <int id> noya2::barrett dynamic_modint<id>::bt(998244353);
using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;
template<typename T>
concept Modint = requires (T &a){
T::mod();
a.inv();
a.val();
a.pow(declval<int>());
};
} // namespace noya2
#line 374 "c.cpp"
using mint = modint998244353;
#line 2 "/Users/noya2/Desktop/Noya2_library/data_structure/segment_tree.hpp"
namespace noya2{
template <class S, S (*op)(S, S), S (*e)()> struct segtree {
public:
segtree() : segtree(0) {}
segtree(int n) : segtree(std::vector<S>(n, e())) {}
segtree(const std::vector<S>& v) : _n(int(v.size())) {
log = 0;
size = 1;
while (size < _n) size <<= 1, log++;
d = std::vector<S>(2 * size, e());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
for (int i = size - 1; i >= 1; i--) {
update(i);
}
}
void set(int p, S x) {
assert(0 <= p && p < _n);
p += size;
d[p] = x;
for (int i = 1; i <= log; i++) update(p >> i);
}
S get(int p) {
assert(0 <= p && p < _n);
return d[p + size];
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= _n);
S sml = e(), smr = e();
l += size;
r += size;
while (l < r) {
if (l & 1) sml = op(sml, d[l++]);
if (r & 1) smr = op(d[--r], smr);
l >>= 1;
r >>= 1;
}
return op(sml, smr);
}
S all_prod() { return d[1]; }
template <bool (*f)(S)> int max_right(int l) {
return max_right(l, [](S x) { return f(x); });
}
template <class F> int max_right(int l, F f) {
assert(0 <= l && l <= _n);
assert(f(e()));
if (l == _n) return _n;
l += size;
S sm = e();
do {
while (l % 2 == 0) l >>= 1;
if (!f(op(sm, d[l]))) {
while (l < size) {
l = (2 * l);
if (f(op(sm, d[l]))) {
sm = op(sm, d[l]);
l++;
}
}
return l - size;
}
sm = op(sm, d[l]);
l++;
} while ((l & -l) != l);
return _n;
}
template <bool (*f)(S)> int min_left(int r) {
return min_left(r, [](S x) { return f(x); });
}
template <class F> int min_left(int r, F f) {
assert(0 <= r && r <= _n);
assert(f(e()));
if (r == 0) return 0;
r += size;
S sm = e();
do {
r--;
while (r > 1 && (r % 2)) r >>= 1;
if (!f(op(d[r], sm))) {
while (r < size) {
r = (2 * r + 1);
if (f(op(d[r], sm))) {
sm = op(d[r], sm);
r--;
}
}
return r + 1 - size;
}
sm = op(d[r], sm);
} while ((r & -r) != r);
return 0;
}
private:
int _n, size, log;
std::vector<S> d;
void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};
} // namespace noya2
#line 377 "c.cpp"
#line 2 "/Users/noya2/Desktop/Noya2_library/misc/timer.hpp"
#line 5 "/Users/noya2/Desktop/Noya2_library/misc/timer.hpp"
namespace noya2{
struct Timer {
private:
std::chrono::high_resolution_clock::time_point start, end;
public:
Timer() { set(); }
void set() { start = std::chrono::high_resolution_clock::now(); }
int time() {
end = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
double dtime(){
return (double)(time()) / 1000;
}
bool before(double T) { return time() < (int)(T * 1000); }
void print() { std::cerr << "elapsed time: " << (double)time() / 1000 << " sec" << std::endl; }
};
} // namespace noya2
#line 379 "c.cpp"
void solve(){
int n; in(n);
string s; in(s);
// s = string(n,'0');
// Timer timer;
s += s;
roriha hs(s);
// kaibun wo mitukeru
vector<int> dp = palindrome_length(s);
rep(i,dp.size()){
chmin(dp[i],n);
if (i % 2 == 0){
if (dp[i] % 2 == 0) dp[i]--;
}
else {
if (dp[i] % 2 == 1) dp[i]--;
}
}
vector<pii> exam;
{
ebi::DualSegtree<int,composition,ideal> seg1(n+n), seg2(n+n);
rep(i,dp.size()){
if (i % 2 == 0){
assert(dp[i] >= 1);
int r = (dp[i]+1)/2;
seg1.apply(i/2,i/2+r,i/2);
}
else {
int r = dp[i]/2;
seg2.apply(i/2+1,i/2+1+r,i/2+1);
}
}
rep(i,n+n){
int mi = seg1.get(i);
int le = mi+mi-i;
exam.emplace_back(le,i+1);
}
rep(i,n+n){
int mi = seg2.get(i);
if (mi == e()) continue;
int le = mi+mi-i-1;
exam.emplace_back(le,i+1);
}
}
// timer.print();
// unique
{
// unordered_set<ull> st;
gp_hash_table<ull,bool> st;
vector<pii> fxam;
for (auto [l, r] : exam){
ull h = hs.get(l,r);
if (st.find(h) != st.end()) continue;
st[h] = true;
fxam.emplace_back(l,r);
}
swap(exam,fxam);
}
// timer.print();
vector<int> sa = atcoder::suffix_array(s);
vector<int> lcp = atcoder::lcp_array(s,sa);
segtree<int,op,e> seg(lcp);
vector<int> inv(sa.size());
rep(i,sa.size()) inv[sa[i]] = i;
vector<int> rui(n+n+1,0);
rep(i,n+n) rui[i+1] = rui[i] + (sa[i] < n ? 1 : 0);
mint ans = 0;
for (auto [l, r] : exam){
int i = inv[l];
int li = seg.min_left(i,[&](int x){
return x >= r-l;
});
int ri = seg.max_right(i,[&](int x){
return x >= r-l;
});
ri++;
mint cnt = rui[ri] - rui[li];
//out(l,r,i,li,ri,cnt);
ans += cnt * cnt * (r-l);
}
out(ans);
}
int main(){
int t = 1; //in(t);
while (t--) { solve(); }
}
这程序好像有点Bug,我给组数据试试?
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 1ms
memory: 3544kb
input:
5 01010
output:
39
result:
ok 1 number(s): "39"
Test #2:
score: 0
Accepted
time: 0ms
memory: 3612kb
input:
8 66776677
output:
192
result:
ok 1 number(s): "192"
Test #3:
score: 0
Accepted
time: 0ms
memory: 3496kb
input:
1 1
output:
1
result:
ok 1 number(s): "1"
Test #4:
score: 0
Accepted
time: 0ms
memory: 3496kb
input:
2 22
output:
12
result:
ok 1 number(s): "12"
Test #5:
score: 0
Accepted
time: 0ms
memory: 3572kb
input:
2 21
output:
2
result:
ok 1 number(s): "2"
Test #6:
score: 0
Accepted
time: 0ms
memory: 3492kb
input:
3 233
output:
10
result:
ok 1 number(s): "10"
Test #7:
score: 0
Accepted
time: 0ms
memory: 3608kb
input:
3 666
output:
54
result:
ok 1 number(s): "54"
Test #8:
score: 0
Accepted
time: 608ms
memory: 184304kb
input:
1000000 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333...
output:
496166704
result:
ok 1 number(s): "496166704"
Test #9:
score: 0
Accepted
time: 1889ms
memory: 579116kb
input:
3000000 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222...
output:
890701718
result:
ok 1 number(s): "890701718"
Test #10:
score: 0
Accepted
time: 1816ms
memory: 579256kb
input:
3000000 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999...
output:
224009870
result:
ok 1 number(s): "224009870"
Test #11:
score: 0
Accepted
time: 1507ms
memory: 532100kb
input:
3000000 8989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989...
output:
51985943
result:
ok 1 number(s): "51985943"
Test #12:
score: 0
Accepted
time: 1481ms
memory: 579824kb
input:
3000000 1911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911911...
output:
355676465
result:
ok 1 number(s): "355676465"
Test #13:
score: 0
Accepted
time: 1942ms
memory: 577892kb
input:
3000000 7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777...
output:
788510374
result:
ok 1 number(s): "788510374"
Test #14:
score: 0
Accepted
time: 1992ms
memory: 579204kb
input:
3000000 5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555...
output:
691884476
result:
ok 1 number(s): "691884476"
Test #15:
score: 0
Accepted
time: 1726ms
memory: 578780kb
input:
3000000 0990990909909909099090990990909909909099090990990909909099099090990990909909099099090990990909909099099090990909909909099099090990909909909099090990990909909909099090990990909909909099090990990909909099099090990990909909099099090990990909909099099090990909909909099099090990909909909099090990...
output:
701050848
result:
ok 1 number(s): "701050848"
Test #16:
score: 0
Accepted
time: 1178ms
memory: 436828kb
input:
3000000 2772772727727727277272772772727727727277272772772727727277277272772772727727277277272772772727727277277272772727727727277277272772727727727277272772772727727727277272772772727727727277272772772727727277277272772772727727277277272772772727727277277272772727727727277277272772727727727277272772...
output:
486861605
result:
ok 1 number(s): "486861605"
Test #17:
score: 0
Accepted
time: 1504ms
memory: 579380kb
input:
3000000 4554554545545545455454554554545545545455454554554545545455455454554554545545455455454554554545545455455454554545545545455455454554545545545455454554554545545545455454554554545545545455454554554545545455455454554554545545455455454554554545545455455454554545545545455455454554545545545455454554...
output:
450625621
result:
ok 1 number(s): "450625621"
Test #18:
score: 0
Accepted
time: 1530ms
memory: 580588kb
input:
3000000 1181811811818118181181181811818118118181181181811818118118181181181811818118118181181811811818118118181181811811818118181181181811811818118181181181811811818118181181181811818118118181181181811818118118181181181811818118118181181811811818118118181181811811818118181181181811811818118181181181...
output:
649551870
result:
ok 1 number(s): "649551870"
Extra Test:
score: 0
Extra Test Passed