Codeforces Round #259 (Div. 1) D. Little Pony and Elements of Harmony FWT

D. Little Pony and Elements of Harmony

在这里插入图片描述

solution

e i [ u ] = ∑ v e i − 1 [ v ] ∗ b [ f ( u , v ) ] . e_i[u]=\sum_{v}e_{i-1}[v]*b[f(u,v)]. ei[u]=vei1[v]b[f(u,v)].

c n t [ u ⊕ v ] = b [ f ( u ⊕ v ) ] cnt[u⊕v]=b[f(u⊕v)] cnt[uv]=b[f(uv)],有:

e i [ u ] = ∑ v e i − 1 [ v ] ∗ c n t [ u ⊕ v ] . e_i[u]=\sum_{v}e_{i-1}[v]*cnt[u⊕v]. ei[u]=vei1[v]cnt[uv].

k = u ⊕ v k=u⊕v k=uv,则:

e i [ u ] = ∑ v = u ⊕ k e i − 1 [ v ] ∗ c n t [ k ] . e_i[u]=\sum_{v=u⊕k}e_{i-1}[v]*cnt[k]. ei[u]=v=ukei1[v]cnt[k]. e i − 1 [ u ] = ∑ v = u ⊕ k e i − 2 [ v ] ∗ c n t [ k ] . e_{i-1}[u]=\sum_{v=u⊕k}e_{i-2}[v]*cnt[k]. ei1[u]=v=ukei2[v]cnt[k]. . . . ... ... e 2 [ u ] = ∑ v = u ⊕ k e 1 [ v ] ∗ c n t [ k ] . e_2[u]=\sum_{v=u⊕k}e_{1}[v]*cnt[k]. e2[u]=v=uke1[v]cnt[k].

= = > ==> ==>

e t [ u ] = ∑ v = u ⊕ k e 0 [ v ] ∗ c n t [ k ] t . e_t[u]=\sum_{v=u⊕k}e_{0}[v]*cnt[k]^t. et[u]=v=uke0[v]cnt[k]t.

预处理 c n t [ k ] cnt[k] cnt[k].

code

/*SiberianSquirrel*//*CuteKiloFish*/
#include <bits/stdc++.h>
//#include<bits/extc++.h>
#include<ext/rope>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
#define gcd(a,b) __gcd(a,b)
#define Inv(x) quick_pow(x, mod - 2)
#define Polynomial vector<int>
#define DEBUG(x, y) cout << x << ": " << y << '\n';
#define mem(a, x) memset(a, x, sizeof a)
#define right_1_pos(x) __builtin_ffs(x)
#define left_0_num(x) __builtin_clz(x)
#define right_0_num(x) __builtin_ctz(x)
#define num_of_1(x) __builtin_popcount(x)
#define Pii pair<int, int>
#define mp_(x, y) make_pair(x, y)
tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> tr;
/*rb_tree_tag 和 splay_tree_tag 选择树的类型(红黑树和伸展树)
null_type//无映射(g++为null_mapped_type)*/
using ld = long double;
using ll = long long;
//using ill = __int128;
using ull = unsigned long long;
using i16 = short;
const ld pi = acos(-1.0);
//const ll mod = 998244353, mod_g = 3, img = 86583718;
ll mod, mod_g = 3, img = 86583718;
int inv2, inv3;
//-----------------------------------------------------------------IO Template
namespace StandardIO {
    template<typename T> inline void read(T &x) {
        x = 0; T f = 1;
        char c = getchar();
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }

    template<typename T> inline void write(T x) {
        if (x < 0) putchar('-'), x *= -1;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace StandardIO;
// -------------------------------------------------------------------------------BASIC_MATH
namespace BASIC_MATH {
    ll mul(ll a, ll b) { ll z = (long double) a / mod * b; ll res = (unsigned long long) a * b - (unsigned long long) z * mod; return (res + mod) % mod; }
    // O(1) quick_mul, use long double
    inline ll quick_pow(ll ans, ll p, ll res = 1) {
        for(; p; p >>= 1, ans = mul(ans, ans) % mod)
            if(p & 1) res = mul(res, ans) % mod;
        return res % mod;
    }
}
using namespace BASIC_MATH;
// -------------------------------------------------------------------------------PRIME
namespace PRIME {
    int prime[int(7e5 + 10)], cnt;
    bool vis[int(7e6 + 10)];
    void get_prime(int n) {
        for (int i = 2; i <= n; ++i) {
            if (!vis[i]) prime[++cnt] = i;
            for (int j = 1; j <= cnt && prime[j] * i <= n; ++j) {
                vis[i * prime[j]] = true;
                if (i % prime[j] == 0) break;
            }
        }
    }
}
//using namespace PRIME;
// -------------------------------------------------------------------------------SOSDP
const int bit = 20;
const int mx = 1 << bit | 1;
void sosdp(vector<int> &a, vector<int> &dp, int n) {
//    for(int i = 0; i <= n; ++ i) dp[i] = 0;
    for(int i = n; i >= 0; ++ i) {
        for(int j = 0; j < bit; ++ j) {
            if((i | (1 << j)) > n) continue;
            dp[i] = (dp[i] + dp[i | (1 << j)]) % mod;
        }
    }
}
// -------------------------------------------------------------------------------PRUFER
namespace FWT {
    inline void OR(ll *f, int n, int x = 1) {
        for (int o = 2; o <= n; o <<= 1) {
            for (int i = 0, k = o >> 1; i < n; i += o) {
                for (int j = 0; j < k; ++j) {
                    f[i + j + k] = (f[i + j + k] + f[i + j] * x % mod + (x == 1 ? 0 : mod)) % mod;
                }
            }
        }
    }
    inline void AND(ll *f, int n, int x = 1) {
        for (int o = 2; o <= n; o <<= 1) {
            for (int i = 0, k = o >> 1; i < n; i += o) {
                for (int j = 0; j < k; ++j) {
                    f[i + j] = (f[i + j] + f[i + j + k] * x + (x == 1 ? 0 : mod)) % mod;
                }
            }
        }
    }
    inline void XOR(ll *f, int n, int x = 1) {
        for (int o = 2; o <= n; o <<= 1) {
            for (int i = 0, k = o >> 1; i < n; i += o) {
                for (int j = 0; j < k; ++j) {
                    f[i + j] += f[i + j + k],
                    f[i + j + k] = f[i + j] - f[i + j + k] - f[i + j + k],
                    f[i + j] *= x, f[i + j + k] *= x;
                    f[i + j] %= mod;
                    f[i + j + k] %= mod;
                    while (f[i + j] < 0) f[i + j] += mod;
                    while (f[i + j + k] < 0) f[i + j + k] += mod;
                }
            }
        }
    }
    inline void OR(vector<ll> &f, int n, int x = 1) {
        for (int o = 2; o <= n; o <<= 1) {
            for (int i = 0, k = o >> 1; i < n; i += o) {
                for (int j = 0; j < k; ++j) {
                    f[i + j + k] = (f[i + j + k] + f[i + j] * x % mod + (x == 1 ? 0 : mod)) % mod;
                }
            }
        }
    }
    inline void AND(vector<ll> &f, int n, int x = 1) {
        for (int o = 2; o <= n; o <<= 1) {
            for (int i = 0, k = o >> 1; i < n; i += o) {
                for (int j = 0; j < k; ++j) {
                    f[i + j] = (f[i + j] + f[i + j + k] * x + (x == 1 ? 0 : mod)) % mod;
                }
            }
        }
    }
    inline void XOR(vector<ll> &f, int n, int x = 1) {
        for (int o = 2; o <= n; o <<= 1) {
            for (int i = 0, k = o >> 1; i < n; i += o) {
                for (int j = 0; j < k; ++ j) {
                    ll X = f[i + j], Y = f[i + j + k];
                    f[i + j] = (X + Y) % mod;
                    f[i + j + k] = ((X - Y) % mod + mod) % mod;
                    // mod is a prime
//                    if(x != 1) {
//                        f[i + j] = f[i + j] * inv2 % mod;
//                        f[i + j + k] = f[i + j + k] * inv2 % mod;
//                    }
                }
            }
        }
        // mod is not a prime, let mod = mod * (1 << m), n = 1 << m;
         if(x != 1) for(int i = 0; i < n; ++ i) {
             f[i] /= n;
         }
    }
}
using namespace FWT;
// -------------------------------------------------------------------------------FWT
namespace PRUFER {
    int n;
    int d[int(5e6 + 10)], f[int(5e6 + 10)], p[int(5e6 + 10)];
    void TtoP() {
        for(int i = 1, j = 1; i <= n - 2; ++ i, ++ j) {
            while(d[j]) ++ j;
            p[i] = f[j];
            while(i <= n - 2 && -- d[p[i]] == 0 && p[i] < j)
                p[i + 1] = f[p[i]], ++ i;
        }
    }
    void PtoT() {
        p[n - 1] = n;
        for(int i = 1, j = 1; i <= n - 1; ++ i, ++ j) {
            while(d[j]) ++ j;
            f[j] = p[i];
            while(i <= n - 1 &&  -- d[p[i]] == 0 && p[i] < j)
                f[p[i]] = p[i + 1], ++ i;
        }
    }
}
//using namespace PRUFER;
// -------------------------------------------------------------------------------MATRIX
namespace MATRIX {
    struct Matrix {
        static const int M = 2;
        double mx[M][M];

        Matrix() { memset(mx, 0, sizeof mx); }

        void Out() {
            for (auto &i : mx) {
                for (auto j : i)
                    cout << j << ' ';
                cout << endl;
            }
        }

        void Tranfer_E() {
            memset(mx, 0, sizeof mx);
            for (int i = 0; i < M; ++i) mx[i][i] = 1;
        }

        Matrix operator*(const struct Matrix a) const {
            Matrix x;
            memset(x.mx, 0, sizeof x.mx);
            for (int i = 0; i < M; ++i)
                for (int j = 0; j < M; ++j)
                    for (int k = 0; k < M; ++k)
                        x.mx[i][j] = (x.mx[i][j] + mx[i][k] * a.mx[k][j]);
            return x;
        }
    };
    Matrix mat_pow(Matrix mx, int p) {
        Matrix res;
        res.Tranfer_E();
        for (; p; p >>= 1, mx = mx * mx)
            if (p & 1) res = res * mx;
        return res;
    }
}
//using namespace MATRIX;
// -------------------------------------------------------------------------------MODINT
namespace MODINT {
    template<unsigned M_> struct ModInt {
        static constexpr unsigned M = M_;
        unsigned x;

        constexpr ModInt() : x(0U) {}

        constexpr ModInt(unsigned x_) : x(x_ % M) {}

        constexpr ModInt(unsigned long long x_) : x(x_ % M) {}

        constexpr ModInt(int x_) : x(((x_ %= static_cast<int>(M)) < 0) ? (x_ + static_cast<int>(M)) : x_) {}

        constexpr ModInt(long long x_) : x(
                ((x_ %= static_cast<long long>(M)) < 0) ? (x_ + static_cast<long long>(M)) : x_) {}

        ModInt &operator+=(const ModInt &a) {
            x = ((x += a.x) >= M) ? (x - M) : x;
            return *this;
        }

        ModInt &operator-=(const ModInt &a) {
            x = ((x -= a.x) >= M) ? (x + M) : x;
            return *this;
        }

        ModInt &operator*=(const ModInt &a) {
            x = (static_cast<unsigned long long>(x) * a.x) % M;
            return *this;
        }

        ModInt &operator/=(const ModInt &a) { return (*this *= a.inv()); }

        ModInt quick_pow(long long e) const {
            if (e < 0) return inv().quick_pow(-e);
            ModInt a = *this, b = 1U;
            for (; e; e >>= 1) {
                if (e & 1) b *= a;
                a *= a;
            }
            return b;
        }

        ModInt inv() const {
            unsigned a = M, b = x;
            int y = 0, z = 1;
            for (; b;) {
                const unsigned q = a / b;
                const unsigned c = a - q * b;
                a = b;
                b = c;
                const int w = y - static_cast<int>(q) * z;
                y = z;
                z = w;
            }
            assert(a == 1U);
            return ModInt(y);
        }

        ModInt operator+() const { return *this; }

        ModInt operator-() const {
            ModInt a;
            a.x = x ? (M - x) : 0U;
            return a;
        }

        ModInt operator+(const ModInt &a) const { return (ModInt(*this) += a); }

        ModInt operator-(const ModInt &a) const { return (ModInt(*this) -= a); }

        ModInt operator*(const ModInt &a) const { return (ModInt(*this) *= a); }

        ModInt operator/(const ModInt &a) const { return (ModInt(*this) /= a); }

        template<class T>
        friend ModInt operator+(T a, const ModInt &b) { return (ModInt(a) += b); }

        template<class T>
        friend ModInt operator-(T a, const ModInt &b) { return (ModInt(a) -= b); }

        template<class T>
        friend ModInt operator*(T a, const ModInt &b) { return (ModInt(a) *= b); }

        template<class T>
        friend ModInt operator/(T a, const ModInt &b) { return (ModInt(a) /= b); }

        explicit operator bool() const { return x; }

        bool operator==(const ModInt &a) const { return (x == a.x); }

        bool operator!=(const ModInt &a) const { return (x != a.x); }

        friend std::ostream &operator<<(std::ostream &os, const ModInt &a) { return os << a.x; }
    };
    constexpr unsigned MO = 998244353;
    using Mint = ModInt<MO>;
}
//using namespace MODINT;
// -------------------------------------------------------------------------------NTT
namespace NTT_ {
    Polynomial R;
//二进制向上取整,为方便NTT变换准备。
    inline int Binary_Rounding(const int &n) {
        int len = 1;
        while (len < n) len <<= 1;
        return len;
    }
//预处理R数组,准备变换,在每次NTT之前理论都要调用此函数。
    inline int Prepare_Transformation(int n) {
        int L = 0, len;
        for (len = 1; len < n; len <<= 1) L++;
        R.clear();
        R.resize(len);
        for (int i = 0; i < len; ++i)
            R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
        return len;
    }
    inline void NTT(Polynomial &a, int f) {
        int n = a.size();
        for (int i = 0; i < n; ++i)
            if (i < R[i])swap(a[i], a[R[i]]);
        for (int i = 1; i < n; i <<= 1)
            for (int j = 0, gn = quick_pow(mod_g, (mod - 1) / (i << 1)); j < n; j += (i << 1))
                for (int k = 0, g = 1, x, y; k < i; ++k, g = 1ll * g * gn % mod)
                    x = a[j + k], y = 1ll * g * a[i + j + k] % mod,
                    a[j + k] = (x + y) % mod, a[i + j + k] = (x - y + mod) % mod;
        if (f == -1) {
            reverse(a.begin() + 1, a.end());
            int inv = Inv(n);
            for (int i = 0; i < n; ++i) a[i] = 1ll * a[i] * inv % mod;
        }
    }
    inline Polynomial operator+(const Polynomial &a, const int &b) {
        int sizea = a.size();
        Polynomial ret = a;
        ret.resize(sizea);
        for (int i = 0; i < sizea; ++i)ret[i] = (1ll * a[i] + b + mod) % mod;
        return ret;
    }
    inline Polynomial operator-(const Polynomial &a, const int &b) {
        int sizea = a.size();
        Polynomial ret = a;
        ret.resize(sizea);
        for (int i = 0; i < sizea; ++i)ret[i] = (1ll * a[i] - b + mod) % mod;
        return ret;
    }
    inline Polynomial operator*(const Polynomial &a, const int &b) {
        int sizea = a.size();
        Polynomial ret = a;
        ret.resize(sizea);
        for (int i = 0; i < sizea; ++i) ret[i] = (1ll * a[i] * b % mod + mod) % mod;
        return ret;
    }
    inline Polynomial operator+(const Polynomial &a, const Polynomial &b) {
        int sizea = a.size(), sizeb = b.size(), size = max(sizea, sizeb);
        Polynomial ret = a;
        ret.resize(size);
        for (int i = 0; i < sizeb; ++i) ret[i] = (1ll * ret[i] + b[i]) % mod;
        return ret;
    }
    inline Polynomial operator-(const Polynomial &a, const Polynomial &b) {
        int sizea = a.size(), sizeb = b.size(), size = max(sizea, sizeb);
        Polynomial ret = a;
        ret.resize(size);
        for (int i = 0; i < sizeb; ++i) ret[i] = (1ll * ret[i] - b[i] + mod) % mod;
        return ret;
    }
    inline Polynomial Inverse(const Polynomial &a) {
        Polynomial ret, inv_a;
        ret.resize(1);
        ret[0] = Inv(a[0]);
        int ed = a.size();
        for (int len = 2; len <= ed; len <<= 1) {
            int n = Prepare_Transformation(len << 1);
            inv_a = a;
            inv_a.resize(n);
            ret.resize(n);
            for (int i = len; i < n; ++i) inv_a[i] = 0;
            NTT(inv_a, 1);
            NTT(ret, 1);
            for (int i = 0; i < n; ++i)
                ret[i] = 1ll * (2ll - 1ll * inv_a[i] * ret[i] % mod + mod) % mod * ret[i] % mod;
            NTT(ret, -1);
            for (int i = len; i < n; ++i) ret[i] = 0;
        }
        ret.resize(ed);
        return ret;
    }
    inline Polynomial operator*(const Polynomial &a, const Polynomial &b) {
        Polynomial lsa = a, lsb = b, ret;
        int n = lsa.size(), m = lsb.size();
        n = Prepare_Transformation(n + m);
        lsa.resize(n);
        lsb.resize(n);
        ret.resize(n);
        NTT(lsa, 1);
        NTT(lsb, 1);
        for (int i = 0; i < n; ++i) ret[i] = 1ll * lsa[i] * lsb[i] % mod;
        NTT(ret, -1);
        return ret;
    }
    inline Polynomial operator/(const Polynomial &a, const Polynomial &b) {
        Polynomial ret = a, ls = b;
        reverse(ret.begin(), ret.end());
        reverse(ls.begin(), ls.end());
        ls.resize(Binary_Rounding(a.size() + b.size()));
        ls = Inverse(ls);
        ls.resize(a.size() + b.size());
        ret = ret * ls;
        ret.resize(a.size() - b.size() + 1);
        reverse(ret.begin(), ret.end());
        return ret;
    }
    inline Polynomial operator%(const Polynomial &a, const Polynomial &b) {
        Polynomial ret = a / b;
        ret = ret * b;
        ret.resize(a.size() + b.size());
        ret = a - ret;
        ret.resize(a.size() + b.size());
        return ret;
    }
    inline Polynomial Derivation(const Polynomial &a) {
        int size = a.size();
        Polynomial ret;
        ret.resize(size);
        for (int i = 1; i < size; ++i) ret[i - 1] = 1ll * i * a[i] % mod;
        ret[size - 1] = 0;
        return ret;
    }
    inline Polynomial Integral(const Polynomial &a) {
        int size = a.size();
        Polynomial ret;
        ret.resize(size);
        for (int i = 1; i < size; ++i) ret[i] = 1ll * Inv(i) * a[i - 1] % mod;
        ret[0] = 0;
        return ret;
    }
    inline Polynomial Composition_Inverse(const Polynomial &a) {
        int n = a.size();
        Polynomial ret, Cinv = a, Pow;
        Cinv.resize(n);
        ret.resize(n);
        Pow.resize(n);
        Pow[0] = 1;
        for (int i = 0; i < n - 1; ++i) Cinv[i] = Cinv[i + 1];
        Cinv[n - 1] = 0;
        Cinv = Inverse(Cinv);
        for (int i = 1; i < n; ++i) {
            Pow = Pow * Cinv;
            Pow.resize(n);
            ret[i] = 1ll * Pow[i - 1] * Inv(i) % mod;
        }
        return ret;
    }
    inline Polynomial Logarithmic(const Polynomial &a) {
        Polynomial ln_a = Derivation(a) * Inverse(a);
        ln_a.resize(a.size());
        return Integral(ln_a);
    }
    inline Polynomial Exponential(const Polynomial &a, int Constant = 1) {
        Polynomial ret, D;
        int ed = a.size();
        ret.resize(1);
        ret[0] = Constant;
        for (int len = 2; len <= ed; len <<= 1) {
            D = Logarithmic(ret);
            D.resize(len);
            D[0] = (1ll * a[0] + 1ll - D[0] + mod) % mod;
            for (int i = 1; i < len; ++i) D[i] = (1ll * a[i] - D[i] + mod) % mod;
            int n = Prepare_Transformation(len << 1);
            ret.resize(n);
            D.resize(n);
            NTT(ret, 1);
            NTT(D, 1);
            for (int i = 0; i < n; ++i) ret[i] = 1ll * ret[i] * D[i] % mod;
            NTT(ret, -1);
            for (int i = len; i < (len << 1); ++i) ret[i] = D[i] = 0;
        }
        ret.resize(ed);
        return ret;
    }
}
//using namespace NTT_;

inline void solve() {
//    inv2 = Inv(2);
    ll m, t, p; cin >> m >> t >> p; ll n = 1 << m; mod = p * n;
    vector<ll> e(n | 1), b(n | 1), cnt(n | 1);
    for(int i = 0; i < n; ++ i) {
        cin >> e[i]; e[i] %= mod;
    }
    for(int i = 0; i < m + 1; ++ i) {
        cin >> b[i]; b[i] %= mod;
    }
    for(int i = 0; i < n; ++ i) {
        cnt[i] = b[num_of_1(i)];
    }
    XOR(cnt, n), XOR(e, n);
    for(int i = 0; i < n; ++ i) {
        cnt[i] = quick_pow(cnt[i], t);
        e[i] = mul(e[i], cnt[i]);
    }
    XOR(e, n, -1);
    for(int i = 0; i < n; ++ i) {
        cout << e[i] << '\n';
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful!" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值