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;
}

 

posted @ 2017-12-19 21:29  ZlycerQan  阅读(171)  评论(0编辑  收藏  举报