• Luogu 3321 [SDOI2015]序列统计


    BZOJ 3992

    点开这道题之后才发现我对原根的理解大概只停留在$998244353$的原根是$3$……

    关于原根: 点我

    首先写出$dp$方程,设$f_{i, j}$表示序列长度为$i$当前所有数乘积模$m$为$j$的方案数,有转移

    $$f_{i, x * y mod m} = sum_{y in s} f_{i - 1, x}$$

    把$x$和$y$取个对数就可以变成卷积的形式了。

    然而在模意义下,我们可以用原根的$k$次方来代替原来的数,这样子就达到了取对数的效果。

    注意到每一次转移形式都是相同的,我们可以用快速幂的方式来优化。

    时间复杂度$O(mlogmlogn)$。

    然而我的代码只有在有$c++11$的时候才是对的,哪位大佬如果知道了为什么教教我呗。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef long long ll;
    typedef vector <ll> poly;
    
    const int N = 8005;
    
    int n, m, tar, fac[N], buc[N];
    
    namespace Poly {
        const int L = 1 << 14;
        const ll P = 1004535809LL;
        
        int lim, pos[L];
        
        template <typename T>
        inline void inc(T &x, T y) {
            x += y;
            if (x >= P) x -= P;
        }
        
        inline ll fpow(ll x, ll y, ll mod = P) {
            ll res = 1;
            for (; y > 0; y >>= 1) {
                if (y & 1) res = res * x % mod;
                x = x * x % mod;
            }
            return res;
        }
        
        inline void prework(int len) {
            int l = 0;
            for (lim = 1; lim < len; lim <<= 1, ++l);
            for (int i = 0; i < lim; i++)
                pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
        }
        
        inline void ntt(poly &c, int opt) {
            c.resize(lim, 0);
            for (int i = 0; i < lim; i++)    
                if (i < pos[i]) swap(c[i], c[pos[i]]);
            for (int i = 1; i < lim; i <<= 1) {
                ll wn = fpow(3, (P - 1) / (i << 1));
                if (opt == -1) wn = fpow(wn, P - 2);
                for (int len = i << 1, j = 0; j < lim; j += len) {
                    ll w = 1;
                    for (int k = 0; k < i; k++, w = w * wn % P) {
                        ll x = c[j + k], y = w * c[j + k + i] % P;
                        c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
                    }
                }
            }
            
            if (opt == -1) {
                ll inv = fpow(lim, P - 2);
                for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P;
            }
        }
        
        poly operator * (const poly x, const poly y) {
            poly u = x, v = y, res;
            prework(x.size() + y.size() - 1);
            ntt(u, 1), ntt(v, 1);
            for (int i = 0; i < lim; i++) res.push_back(u[i] * v[i] % P);
            ntt(res, -1);
            res.resize(x.size() + y.size() - 1);
            return res;
        }
        
        inline void adj(poly &c) {
            for (int i = 0; i < m - 1; i++) inc(c[i], c[i + m - 1]);
            c.resize(m - 1);
        }
        
        inline poly pow(poly x, int y) {
            poly res;
            res.resize(m - 1);
            res[0] = 1;
            for (; y; y >>= 1) {
                if (y & 1) res = res * x, adj(res);
                x = x * x, adj(x);
            }    
            return res;
        }
        
    }
    
    using Poly :: P;
    using Poly :: fpow;
    using Poly :: pow;
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for (; ch > '9'|| ch < '0'; ch = getchar())
            if (ch == '-') op = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline int getRoot() {
        int cnt = 0;
        for (int i = 2; i <= m - 2; i++)
            if ((m - 1) % i == 0) fac[++cnt] = i;
        for (int i = 2; ; i++) {
            bool flag = 1;
            for (int j = 1; j <= cnt; j++)
                if (fpow(i, fac[j], m) == 1) {
                    flag = 0;
                    break;
                }
            if (flag) return i;
        }
    }
    
    int main() {
    /*    #ifndef ONLINE_JUDGE
            freopen("8.in", "r", stdin);
        #endif   */
        
        int s, root;
        read(n), read(m), read(tar), read(s);
        
        root = getRoot();
        for (int i = 1; i <= m - 2; i++) buc[fpow(root, i, m)] = i;
        
        poly trans;
        trans.resize(m - 1);
        for (int x, i = 1; i <= s; i++) {
            read(x);
            if (!x) continue;
            trans[buc[x]] = 1;
        }
        poly ans = pow(trans, n);
        
        printf("%lld
    ", ans[buc[tar]]);
        return 0;
    }
    View Code
  • 相关阅读:
    Mysql基本操作、C++Mysql简单应用、PythonMysql简单应用
    Mysql安装步骤
    MVC EF 移除建表时自动加上s的复数形式
    MVC autofac 属性注入
    layui table默认选中指定行
    js slice 假分页
    sql 根据身份证号码计算年龄
    pointer-events: none
    /Date(1555554794000)/ 转换为日期格式
    sql 查询字段如果为null 则返回0的写法
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10289484.html
Copyright © 2020-2023  润新知