zoukankan      html  css  js  c++  java
  • BZOJ 3992: [SDOI2015]序列统计

    二次联通门 : BZOJ 3992: [SDOI2015]序列统计

    /*
        BZOJ 3992: [SDOI2015]序列统计
    
        先求出原根
        然后化乘为加
        
        求出母函数
        快速幂 + NTT 即可
    */
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    
    typedef long long LL;
    #define mo 1004535809
    #define rg register
    #define Max 17000
    LL G, p[Max], a[Max], b[Max], f[Max], g[Max];
    int T, rd[Max], is[Max];
    inline void read (int &n)
    {
        rg char c = getchar ();
        for (n = 0; !isdigit (c); c = getchar ());
        for (; isdigit (c); n = n * 10 + c - '0', c = getchar ());
    }
    inline LL pls (LL a, LL b) { a += b; return a >= mo ? a - mo : a; }
    inline LL dec (LL a, LL b) { a -= b; return a < 0 ? a + mo : a; }
    inline LL pow (LL x, LL y, LL p)
    {
        LL res = 1;
        for (; y; y >>= 1, (x *= x) %= p)
            if (y & 1) (res *= x) %= p;
        return res;
    }
    int Calc (int x)
    {
        if (x == 2) return 1; bool F;
        for (rg int i = 2, j; i; ++ i)
        {
            F = true;
            for (j = 2; j * j < x; ++ j)
                if (pow (i, (x - 1) / j, x) == 1)
                { F = false; break; }
            if (F) return i;
        }
    }
    
    LL inv;
    void NTT (LL *a, int N, int f = 1)
    {
        rg int i, j, k; LL wn, w, x, y;
        for (i = 0; i < N; ++ i) if (rd[i] > i) std :: swap (a[i], a[rd[i]]);
        for (k = 1; k < N; k <<= 1)
        {
            wn = pow (3, (mo - 1) / (k << 1), mo);
            for (j = 0; j < N; j += k << 1)
                for (w = 1, i = 0; i < k; ++ i, (w *= wn) %= mo)
                    x = a[i + j], y = a[i + j + k] * w % mo, a[i + j] = pls (x, y), a[i + j + k] = dec (x, y);
        }
        if (f == -1) std :: reverse (a + 1, a + N);
    }
    void mul (LL *g, LL *f, int N, int M)
    {
        rg int i;
        for (i = 0; i < N; ++ i) a[i] = g[i] % mo, b[i] = f[i] % mo;
    
        NTT (a, N), NTT (b, N);
        for (i = 0; i < N; ++ i) (a[i] *= b[i]) %= mo;
        NTT (a, N, -1);
        for (i = 0; i < N; ++ i) (a[i] *= inv) %= mo;
        for (i = 0; i < M - 1; ++ i)
            g[i] = (a[i] + a[i + M - 1]) % mo;
    }
    int main (int argc, char *argv[])
    {
        int N, M, X, S, P, C, x; rg int i, j;
        scanf ("%d%d%d%d", &C, &M, &X, &S); G = Calc (M);
        for (i = 1; i <= S; ++ i)
            read (x), is[x] = 1;
        int pos = -1, L = 0;
        for (i = 0, j = 1; i < M - 1; ++ i, (j *= G) %= M)
        {
            if (is[j]) f[i] = 1;
            if (j == X) pos = i;
        }
            
        P = (M - 1) << 1;
        for (N = 1; N <= P; N <<= 1, ++ L);
        for (i = 0; i < N; ++ i)
            rd[i] = (rd[i >> 1] >> 1) | ((i & 1) << (L - 1));
        inv = pow (N, mo - 2, mo);
        for (g[0] = 1; C; C >>= 1, mul (f, f, N, M))
            if (C & 1) mul (g, f, N, M);
    
        if (pos != -1) std :: cout << g[pos] % mo;
        else puts ("0");
    
        return 0;
    }
  • 相关阅读:
    ajax请求地址后加随机数防止浏览器缓存
    全新跨平台版本.NET敏捷开发框架-RDIFramework.NET5.0震撼发布
    一网打尽,一文讲通虚拟机VirtualBox及Linux使用
    解放双手,markdown文章神器,Typora+PicGo+七牛云图床实现自动上传图片
    VS2019 创建C++动态库dll----C#调用
    AOP面向切面的编程使用Interceptor内置的容器进行属性注入
    使用IOC内置的容器进行属性注入
    对于2021年整体预判
    亲子教育的六个阶段
    Win10 损坏硬盘命令
  • 原文地址:https://www.cnblogs.com/ZlycerQan/p/8067825.html
Copyright © 2011-2022 走看看