[题解]Wordle不是一次就能解决问题吗?

\[\color{red}{\text{校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\ \begin{array}{|} \hline \color{pink}{\text{The principal is really a god}} \\ \color{pink}{\text{with a closestool on the left and Yongshen on the right}} \\ \color{pink}{\text{holding a sharp pen to pierce the truth}} \\ \color{pink}{\text{Who can resist him? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{green}{\text{校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり}} \\ \color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{lightblue}{\text{Le principal est vraiment un dieu}} \\ \color{lightblue}{\text{avec des toilettes à gauche et Yongshen à droite}} \\ \color{lightblue}{\text{tenant un stylo pointu pour percer la vérité}} \\ \color{lightblue}{\text{Qui peut lui résister ? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\ \color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\ \color{purple}{\text{der einen spitzen Stift hält}} \\ \color{purple}{\text{um die Wahrheit zu durchdringen.}} \\ \color{purple}{\text{Wer kann ihm widerstehen? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{cyan}{\text{Principalis deus est, Yongshen a dextris cum latrina}} \\ \color{cyan}{\text{acuto stylo ad perforandum veritatem: quis resistet ei? }} \\ \hline \end{array} \\ \color{red}{\text{对曰:“无人,狗欲当之,还请赐教!”}} \\ \newcommand\brak[1]{\left({#1}\right)} \newcommand\Brak[1]{\left\{{#1}\right\}} \newcommand\d[0]{\text{d}} \newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}} \newcommand\down[2]{{#1}^{\underline{#2}}} \newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor} \newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil} \newcommand\lcm[0]{\operatorname{lcm}} \newcommand\set[1]{\left\{{#1}\right\}} \newcommand\ceil[1]{\left\lceil{#1}\right\rceil} \newcommand\floor[1]{\left\lfloor{#1}\right\rfloor} \newcommand\rhs[1]{\;\text{Rhs}\;#1} \newcommand\lhs[1]{\;\text{Lhs}\;#1} \newcommand\Vec[1]{\vec{\mathbf{#1}}} \newcommand\rank[0]{\text{rank}} \]

  \(\mathcal{Back\;To\;The\;Menu}\).

2022-03-16 Wordle不是一次就能解决问题吗?

  怎么说呢,感觉自己还是代码能力太弱了......T1 一个朴素的分块都可以写这么久,着实不应该啊。

传教 / Mission

  先定义 \(c_i=a_i\oplus b_i\),最后的目标就是把 \(c_i\) 全部变成 \(0\).

  由于是区间操作,所以你可以做一个差分:\(s_i=c_i\oplus c_{i-1}\),并且目标不变 —— 将 \(s_i\) 全部变为 \(0\).

  对于一个区间整体异或一个数,实际上就是把差分数组的 \(s_i,s_{i+k}\) 同时异或一个数,你会发现,经过这个操作后,下标余数相同的数的异或和不变,然后你就会判断无解了 —— 某个下标与 \(k\) 余数相同的 \(s_i\) 异或和不为 \(0\).

  判断无解的条件给了你思路 —— 将所有数按照膜 \(k\) 剩余系分组。对于同一剩余系中的数,按照下标排列好,不需要执行的异或传递就是前缀异或和为 \(0\) 的位置个数,也就是说,我们要动态维护每个剩余系下前缀异或和为 \(0\) 的位置个数。

  线段树等 \(\mathcal O(\text{polylog})\) 的算法显然是不行的,考虑分块维护,因为 \(s_i\le 2^{15}\)。显然可以每个块开一个桶维护一下。

  但是你发现 \(k\) 比较大的时候,剩余系本来就比较小,再开桶就显得小题大做 MLE,因此可以对于 \(k\) 进行根号分治:

  • \(k>\sqrt n\) 的时候,直接暴力维护剩余系前缀异或和;
  • \(k\le \sqrt n\) 时,每个剩余系分块维护;

  然后就做完了,时间复杂度 \(\mathcal O(n\sqrt n)\). 不知道为什么下面这份代码只有 \(85pts\),听说有些数据有点问题(但是好像只有一组),但是我也懒得管了......

/** @author __Elaina__ */

// #pragma GCC optimize("O2")

#include <bits/stdc++.h>
using namespace std;

// #define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
    return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
    return min(x, listMin(args...));
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 2e5;
const int Sqn = 450;
const int Maxa = 1 << 15;
const int Maxk = 2e5;

int n, k, q;
int a[Maxn + 5], b[Maxn + 5], s[Maxn + 5];

inline void input() {
    readin(n, k, q);
    repf (i, 0, n) readin(a[i]);
    repf (i, 0, n) readin(b[i]);
    repf (i, 0, n) s[i] = a[i] ^ b[i];
    drep (i, n - 1, 0) s[i] ^= s[i - 1];
    // repf (i, 0, n) masdf("s[%d] == %d\n", i, s[i]);
}

int cnt0 = 0, allzero = 0;
struct residueDividePart {

    bool F__K_SPECIAL;
    int len, id, xorsum;    // the length of this residue & the total id of blocks & the xor sum
    vector<int> pre;        // the presum of the origin array
    vector<int> bel;        // the belong of each position
    // below are block info
    vector<vset> cnt;       // counter for each block
    vector<int> blef, brig; // the left & right endpos of each block
    vector<int> tag;        // lazy tag

    inline void init(const vset& arr) {
        // masdf("init :> "); for (const int& x: arr) masdf("%d ", x); Endl;
        len = arr.size();
        pre.resize(len), bel.resize(len);
        xorsum = pre[0] = arr[0];
        cnt0 += (pre[0] == 0);
        repf (i, 1, len) {
            pre[i] = pre[i - 1] ^ arr[i];
            cnt0 += (pre[i] == 0);
            xorsum = pre[i];
            // masdf("When i == %d, pre[%d] == %d, xorsum == %d\n", i, i, pre[i], xorsum);
        }
        for (id = 1; id * Sqn < len; ++id);
        blef.resize(id), brig.resize(id), tag.resize(id), cnt.resize(id);
        repf (i, 0, id) {
            blef[i] = i * Sqn, brig[i] = min((i + 1) * Sqn, len);
            cnt[i].resize(Maxa);
            repf (j, blef[i], brig[i]) ++cnt[i][pre[j]];
        }
        if (!F__K_SPECIAL) allzero += (xorsum != 0);
    }

    inline void rebuild(int i) {
        if (!tag[i]) return ;
        cnt0 -= cnt[i][tag[i]];
        repf (j, blef[i], brig[i]) {
            --cnt[i][pre[j]];
            ++cnt[i][pre[j] ^= tag[i]];
        }
        cnt0 += cnt[i][tag[i] = 0];
    }

    inline void modify(int p, int x) {
        if (!x) return ;
        assert(p < len);
        if (!F__K_SPECIAL) allzero -= (xorsum != 0);
        xorsum ^= x;
        if (!F__K_SPECIAL) allzero += (xorsum != 0);
        rebuild(bel[p]);
        repf (i, p, brig[bel[p]]) {
            cnt0 -= (pre[i] == 0);
            --cnt[bel[p]][pre[i]];
            pre[i] ^= x;
            cnt0 += (pre[i] == 0);
            ++cnt[bel[p]][pre[i]];
        }
        repf (i, bel[p] + 1, id) {
            cnt0 -= cnt[i][tag[i]];
            tag[i] ^= x;
            cnt0 += cnt[i][tag[i]];
        }
        // masdf("xorsum == %d, cnt0 == %d\n", xorsum, cnt0);
    }

} Arrs[Maxk + 5];

int pos[Maxn + 5]; // the position of the element in its residue group

inline void prelude() {
    vector<int> arr;
    repf (i, 0, k) {
        arr.clear(); int p = 0;
        for (int j = i; j < n; j += k) {
            arr.push_back(s[j]);
            pos[j] = p++;
        }
        if (n % k == i) Arrs[i].F__K_SPECIAL = true;
        else Arrs[i].F__K_SPECIAL = false;
        Arrs[i].init(arr);
    }
}

inline void solve() {
    char op[5]; int x, y;
    if (allzero) puts("-1");
    else printf("%d\n", n - cnt0);
    while (q--) {
        scanf("%s %d %d", op, &x, &y), --x;
        if (*op == 'a') {
            int delt = a[x] ^ y;
            a[x] = y;
            Arrs[x % k].modify(pos[x], delt);
            if (x + 1 < n) Arrs[(x + 1) % k].modify(pos[x + 1], delt);
        }
        else {
            int delt = b[x] ^ y;
            b[x] = y;
            Arrs[x % k].modify(pos[x], delt);
            if (x + 1 < n) Arrs[(x + 1) % k].modify(pos[x + 1], delt);
        }
        if (allzero) puts("-1");
        else printf("%d\n", n - cnt0);
    }
}

namespace Brute {

int cnt0 = 0, allzero = 0;
struct residueDividePart {

    bool F__K_SPECIAL;
    int len, xorsum;
    vector<int> pre;

    inline void init(const vset& arr) {
        pre.resize(len = arr.size());
        xorsum = pre[0] = arr[0];
        cnt0 += (pre[0] == 0);
        repf (i, 1, len) {
            pre[i] = pre[i - 1] ^ arr[i];
            cnt0 += (pre[i] == 0);
            xorsum = pre[i];
        }
        if (!F__K_SPECIAL) allzero += (xorsum != 0);
    }

    inline void modify(int p, int x) {
        if (!x) return ;
        assert(p < len);
        if (!F__K_SPECIAL) allzero -= (xorsum != 0);
        xorsum ^= x;
        if (!F__K_SPECIAL) allzero += (xorsum != 0);
        repf (i, p, len) {
            cnt0 -= (pre[i] == 0);
            pre[i] ^= x;
            cnt0 += (pre[i] == 0);
        }
        // masdf("xorsum == %d, cnt0 == %d\n", xorsum, cnt0);
    }

} Arrs[Maxk + 5];

int pos[Maxn + 5]; // the position of the element in its residue group

inline void prelude() {
    vector<int> arr;
    repf (i, 0, k) {
        arr.clear(); int p = 0;
        for (int j = i; j < n; j += k) {
            arr.push_back(s[j]);
            pos[j] = p++;
        }
        if (n % k == i) Arrs[i].F__K_SPECIAL = true;
        else Arrs[i].F__K_SPECIAL = false;
        Arrs[i].init(arr);
    }
}

inline void solve() {
    char op[5]; int x, y;
    if (allzero) puts("-1");
    else printf("%d\n", n - cnt0);
    while (q--) {
        scanf("%s %d %d", op, &x, &y), --x;
        if (*op == 'a') {
            int delt = a[x] ^ y;
            a[x] = y;
            Arrs[x % k].modify(pos[x], delt);
            if (x + 1 < n) Arrs[(x + 1) % k].modify(pos[x + 1], delt);
        }
        else {
            int delt = b[x] ^ y;
            b[x] = y;
            Arrs[x % k].modify(pos[x], delt);
            if (x + 1 < n) Arrs[(x + 1) % k].modify(pos[x + 1], delt);
        }
        if (allzero) puts("-1");
        else printf("%d\n", n - cnt0);
    }
}

inline void work() {
    prelude();
    solve();
}

} // namespace Brute

signed main() {
    freopen("mission.in", "r", stdin);
    freopen("mission.out", "w", stdout);
    input();
    if (k <= Sqn) {
        prelude();
        solve();
    }
    else Brute::work();
    return 0;
}

方程 / Equation

  显然是要我们对这个式子动手脚的,它说要动就动呗,毕竟它也只给了我们这个式子啊......注意看原来的式子,你会发现稍微变形之后 \(a+b\) 都是一起出现的,这提示我们可以换元:

\[\begin{align} \frac{(a+c)(a-c)+b(2a+b)}{ac+bc}-\frac{(a+b+c)(a+b)+c^2}{c^2}-t&\equiv 0\pmod p \\ \frac{(a+b)^2-c^2}{(a+b)c}-\frac{(a+b+c)(a+b)+c^2}{c^2}&\equiv t\pmod p \tag{1} \\ \frac{x^2-c^2}{cx}-\frac{(x+c)x+c^2}{c^2}&\equiv t\pmod p&\brak{a+b\overset\Delta=x} \tag{2} \end{align} \]

  其实有 \((2)\) 你就可以进行 \(\mathcal O(n^2)\) 的算法,常数小一点有 \(60pts\)(但是我看在场好像还没有超级无敌小常数的诶~~)把 \(a+b\) 换元之后可以得到 \((3)\). 有了 \((3)\),你可以很容易发现:若 \((x,c)\) 满足条件,那么 \((kx,kc)\) 也满足条件,因为所有项都是二次项,同时乘以一个系数也不影响。

  于是我们可以只需要统计 \(c=1\) 的情况,其他情况直接用 \(k\) 进行调整。

  接下来有几个问题:一是 \(a+b\equiv i\pmod p\) 有多少组,这个直接上 NTT 就行了。

  其二,我们最终要计算的是 \(kx(k\in S)\),即算出一个 \((x,1)\) 之后,我们实际上要找到 \((kx,k)(k\in S)\) 的方案数,即对于一个 \(x\),有多少 \(x,k\) 的方案数达到 \(kx\),可以考虑使用原根 \(g\),将 \(kx\) 表示为 \(g^u\times g^v\),其中 \(k=g^u,x=g^v\),这就又变成一个背包问题了,使用 NTT 同样可以解决。然后就解决了,总复杂度 \(\mathcal O(n\log n)\).

/** @author __Elaina__ */

// #pragma GCC optimize("O2")

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI ((char)getchar())
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
    return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
    return min(x, listMin(args...));
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 4e5;
const int mod = 998244353;
inline void chkadd(int& x, int y) { if ((x += y) >= mod) x -= mod; }

inline int qkpow(int a, int n) {
    int ret = 1;
    for (; n; n >>= 1, a = (int)(1ll * a * a % mod))
        if (n & 1) ret = (int)(1ll * ret * a % mod);
    return ret;
}
inline int qkpow(int a, int n, int mod) {
    int ret = 1;
    for (; n; n >>= 1, a = (int)(1ll * a * a % mod))
        if (n & 1) ret = (int)(1ll * ret * a % mod);
    return ret;
}

namespace Poly {

int G[55];
int rev[Maxn << 2 | 2], n, invn;
inline void Initialization() {
    rep (i, 1, 23) G[i] = qkpow(3, mod - 1 >> i);
}
struct _Initer {
    _Initer() { Initialization(); }
} _initer;
inline void init(int len) {
    for (n = 1; n < len; n <<= 1);
    repf (i, 1, n) rev[i] = (rev[i >> 1] >> 1) | ((i & 1)? n >> 1: 0);
    invn = qkpow(n, mod - 2);
}
inline void ntt(vset& f, int opt) {
    f.resize(n);
    repf (i, 1, n) if (i < rev[i]) swap(f[i], f[rev[i]]);
    for (int p = 2, lev = 1; p <= n; p <<= 1, ++lev) {
        int len = p >> 1, w = G[lev];
        for (int k = 0; k < n; k += p) {
            for (int i = k, buf = 1; i < k + len; ++i, buf = (int)(1ll * buf * w % mod)) {
                int tmp = (int)(1ll * f[i + len] * buf % mod);
                f[i + len] = (f[i] + mod - tmp) % mod;
                f[i] = (f[i] + tmp) % mod;
            }
        }
    }
    if (opt == -1) { // DFT
        reverse(f.begin() + 1, f.end());
        for (int& x: f) x = (int)(1ll * x * invn % mod);
    }
}

inline vset convolution(vset a, vset b) {
    int len = (int)(a.size() + b.size()) - 1;
    init(len), ntt(a, 0xcbdd1), ntt(b, 0xCBDD1);
    for (int i = 0; i < n; ++i)
        a[i] = (int)(1ll * a[i] * b[i] % mod);
    return ntt(a, -1), a.resize(len), a;
}

inline void doubleIt(vset& a) {
    int len = (int)(a.size() << 1) - 1;
    init(len), ntt(a, 0xcbdd1);
    for (int i = 0; i < n; ++i)
        a[i] = (int)(1ll * a[i] * a[i] % mod);
    ntt(a, -1), a.resize(len);
}

} // namespace NTT

int s[Maxn + 5], t[Maxn + 5], n, m, p, gp;

inline vset divide(int x) {
    vset ret;
    for (int i = 2; i * i <= x; ++i) if (x % i == 0) {
        ret.push_back(i);
        while (x % i == 0) x /= i;
    }
    if (x > 1) ret.push_back(x);
    return ret;
}

inline int findroot(int p) {
    vset div = divide(p - 1);
    for (int i = 2; ; ++i) {
        bool yes = true;
        for (const auto& d: div) {
            if (qkpow(i, (p - 1) / d, p) == 1) {
                yes = false; break;
            }
        }
        if (yes) return i;
    }
}

inline void input() {
    readin(p, n, m);
    rep (i, 1, n) readin(s[i]);
    rep (i, 1, m) readin(t[i]);
    gp = findroot(p);
}

int invInp[Maxn + 5], pwof[Maxn + 5];
inline void prelude() {
    invInp[0] = invInp[1] = 1;
    repf (i, 2, p) invInp[i] = (int)(1ll * (p - p / i) * invInp[p % i] % p);
    pwof[1] = 0;
    for (int cur = gp, q = 1; cur != 1; cur = (int)(1ll * cur * gp % p), ++q)
        pwof[cur] = q;
}
vset buc, pwbuc, pws;
inline void work() {
    buc.resize(p);
    rep (i, 1, n) ++buc[s[i]];
    Poly::doubleIt(buc);
    repf (i, p, p << 1) chkadd(buc[i - p], buc[i]);
    buc.resize(p);
    pwbuc.resize(p - 1), pws.resize(p - 1);
    repf (i, 1, p) pwbuc[pwof[i]] = buc[i];
    rep (i, 1, n) if (s[i]) pws[pwof[invInp[s[i]]]] = 1;
    pwbuc = Poly::convolution(pwbuc, pws);
    repf (i, p - 1, (p - 1 << 1) - 1) chkadd(pwbuc[i - (p - 1)], pwbuc[i]);
    pwbuc.resize(p - 1);
}

bool inT[Maxn + 5];
inline void calc() {
    rep (i, 1, m) inT[t[i]] = true;
    int ans = 0;
    repf (i, 1, p) {
        int tar = (1ll * i * i + 1 + invInp[i]) % p;
        if (tar) tar = p - tar;
        if (inT[tar]) chkadd(ans, pwbuc[pwof[i]]);
    }
    writln(ans);
}

signed main() {
    freopen("equation.in", "r", stdin);
    freopen("equation.out", "w", stdout);
    input();
    prelude();
    work();
    calc();
    return 0;
}

  暂时先咕掉。

posted @ 2022-03-19 16:31  Arextre  阅读(91)  评论(0编辑  收藏  举报