• xjoi 2082: 小明的序列


    维护一个序列,初始全为(1)

    支持两种操作:

    1.对于所有的位置(i),将它的值乘上(i + a)

    2.询问(a)处的值

    (q=120000) 20s 512M

    ——————

    如果把第一个操作看成乘上一个(x + a_i),第二个操作看成询问(x = a_i)处多项式的值,那么这是一个裸的动态多点求值

    首先暴力是可以AC的……恩,开个O2就行……

    直接上CDQ+静态多点求值的话是(O(n log ^3 n))的,只能跑过60分

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    
    
    const int N = 500000;
    const int MOD = 802160641;
    const int G = 11;
    int powi(int a, int b)
    {
        int c = 1;
        for (; b; b >>= 1, a = 1ll * a * a % MOD)
            if (b & 1) c = 1ll * c * a % MOD;
        return c;
    }
    void NTT(int A[], int n, int f)
    {
        for (int i = 1; i < n; ++ i)
        {
            int j = 0;
            for (int p = 1, q = n >> 1; p < n; p <<= 1, q >>= 1)
                if (i & p) j |= q;
            if (i < j) swap(A[i], A[j]);
        }
        for (int i = 2; i <= n; i <<= 1)
        {
            int w1 = powi(G, (MOD - 1) / i);
            if (f < 0) w1 = powi(w1, MOD - 2);
            for (int j = 0; j < n; j += i)
            {
                int w = 1;
                for (int k = j; k < j + (i >> 1); ++ k)
                {
                    int u = A[k], v = 1ll * A[k + (i >> 1)] * w % MOD;
                    A[k] = (u + v) % MOD;
                    A[k + (i >> 1)] = (u - v + MOD) % MOD;
                    w = 1ll * w * w1 % MOD;
                }
            }
        }
    
        int p = powi(n, MOD - 2);
        if (f < 0) for (int i = 0; i < n; ++ i) A[i] = 1ll * A[i] * p % MOD;
    }
    
    
    int Rev_tmp1[N], Rev_tmp2[N];
    void Rev(int A[], int G[], int n)
    {
        if (n == 1)
        {
            G[0] = powi(A[0], MOD - 2);
        }
        else
        {
            Rev(A, G, n / 2);
            for (int i = 0; i < n; ++ i) Rev_tmp1[i] = A[i];
            for (int i = n; i < (n << 1); ++ i) Rev_tmp1[i] = 0;
            for (int i = 0; i < (n >> 1); ++ i) Rev_tmp2[i] = G[i];
            for (int i = (n >> 1); i < (n << 1); ++ i) Rev_tmp2[i] = 0;
            NTT(Rev_tmp1, n << 1, 1);
            NTT(Rev_tmp2, n << 1, 1);
            for (int i = 0; i < (n << 1); ++ i) Rev_tmp1[i] = ((2 - 1ll * Rev_tmp1[i] * Rev_tmp2[i]) % MOD + MOD) * Rev_tmp2[i] % MOD;
            NTT(Rev_tmp1, n << 1, -1);
            for (int i = 0; i < n; ++ i) G[i] = Rev_tmp1[i];
        }
    }
    
    int Mod_tmp1[N], Mod_tmp2[N], Mod_tmp3[N], Mod_tmp4[N];
    void Mod(int A[], int B[], int D[], int n, int m)
    {
        if (n < m)
        {
            for (int i = 0; i < n; ++ i) D[i] = A[i];
            return;
        }
        int nn = 1;
        while (nn < (n - m + 1)) nn <<= 1;
        for (int i = 0; i < n; ++ i) Mod_tmp3[i] = A[i];
        for (int i = 0; i < m; ++ i) Mod_tmp4[i] = B[i];
        for (int i = 0, j = n - 1; i < j; ++ i, -- j) swap(Mod_tmp3[i], Mod_tmp3[j]);
        for (int i = 0, j = m - 1; i < j; ++ i, -- j) swap(Mod_tmp4[i], Mod_tmp4[j]);
        for (int i = m; i < nn; ++ i) Mod_tmp4[i] = 0;
        Rev(Mod_tmp4, Mod_tmp2, nn);
    
        for (int i = 0; i < n - m + 1; ++ i) Mod_tmp1[i] = Mod_tmp3[i];
        for (int i = n - m + 1; i < (nn << 1); ++ i) Mod_tmp1[i] = 0;
        for (int i = n - m + 1; i < (nn << 1); ++ i) Mod_tmp2[i] = 0;
        NTT(Mod_tmp1, nn << 1, 1);
        NTT(Mod_tmp2, nn << 1, 1);
        for (int i = 0; i < (nn << 1); ++ i) Mod_tmp1[i] = 1ll * Mod_tmp1[i] * Mod_tmp2[i] % MOD;
        NTT(Mod_tmp1, nn << 1, -1);
    
        while (nn < n) nn <<= 1;
        for (int i = 0, j = n - m; i < j; ++ i, -- j) swap(Mod_tmp1[i], Mod_tmp1[j]);
        for (int i = n - m + 1; i < (nn << 1); ++ i) Mod_tmp1[i] = 0;
        for (int i = 0; i < m; ++ i) Mod_tmp2[i] = B[i];
        for (int i = m; i < (nn << 1); ++ i) Mod_tmp2[i] = 0;
        NTT(Mod_tmp1, nn << 1, 1);
        NTT(Mod_tmp2, nn << 1, 1);
        for (int i = 0; i < (nn << 1); ++ i) Mod_tmp1[i] = 1ll * Mod_tmp1[i] * Mod_tmp2[i] % MOD;
        NTT(Mod_tmp1, nn << 1, -1);
    
        for (int i = 0; i < m - 1; ++ i) D[i] = (A[i] - Mod_tmp1[i] + MOD) % MOD;
    }
    
    int AAA[N];
    int Mul_tmp[20][N], Mul_tmp1[N], Mul_tmp2[N];
    void Mul(int x, int l, int r)
    {
        if (r - l == 1)
        {
            Mul_tmp[x][l * 2 + 1] = 1;
            Mul_tmp[x][l * 2] = AAA[l];
            return;
        }
        int m = (l + r) / 2;
        Mul(x + 1, l, m);
        Mul(x + 1, m, r);
        for (int i = 0; i < ((m - l) << 1); ++ i) Mul_tmp1[i] = Mul_tmp[x + 1][i + l * 2];
        for (int i = 0; i < ((r - m) << 1); ++ i) Mul_tmp2[i] = Mul_tmp[x + 1][i + m * 2];
        int nn = 1;
        while (nn < (r - l) * 2) nn <<= 1;
        for (int i = ((m - l) << 1); i < nn; ++ i) Mul_tmp1[i] = 0;
        for (int i = ((r - m) << 1); i < nn; ++ i) Mul_tmp2[i] = 0;
        NTT(Mul_tmp1, nn, 1);
        NTT(Mul_tmp2, nn, 1);
        for (int i = 0; i < nn; ++ i) Mul_tmp1[i] = 1ll * Mul_tmp1[i] * Mul_tmp2[i] % MOD;
        NTT(Mul_tmp1, nn, -1);
        for (int i = 0; i < ((r - l) << 1); ++ i) Mul_tmp[x][i + l * 2] = Mul_tmp1[i];
    }
    
    int get_val_tmp[20][N];
    void get_val(int fin[], int x, int l, int r)
    {
        if (r - l == 1)
        {
            fin[l] = get_val_tmp[x][l * 2];
            return;
        }
        int m = (l + r) / 2;
        Mod(get_val_tmp[x] + l * 2, Mul_tmp[x + 1] + l * 2, get_val_tmp[x + 1] + l * 2, (r - l) * 2, (m - l) + 1);
        Mod(get_val_tmp[x] + l * 2, Mul_tmp[x + 1] + m * 2, get_val_tmp[x + 1] + m * 2, (r - l) * 2, (r - m) + 1);
    
        for (int i = m + l; i < m * 2; ++ i) get_val_tmp[x + 1][i] = 0;
        for (int i = r + m; i < r * 2; ++ i) get_val_tmp[x + 1][i] = 0;
    
        get_val(fin, x + 1, l, m);
        get_val(fin, x + 1, m, r);
    }
    
    void GGG(int A[], int B[], int D[], int n, int m)
    {
        for (int i = 0; i < m * 2; ++ i) get_val_tmp[0][i] = 0;
        for (int i = 0; i < m; ++ i) AAA[i] = MOD - B[i];
        Mul(0, 0, m);
        Mod(A, Mul_tmp[0], get_val_tmp[0], n, m + 1);
        get_val(D, 0, 0, m);
    }
    
    int typ[N], val[N], ans[N];
    
    int solve_tmp1[N], solve_tmp2[N], solve_tmp3[N];
    void solve(int l, int r)
    {
        if (r - l == 1) return;
        int m = (l + r) / 2;
        solve(l, m);
        solve(m, r);
        int tot1 = 0, tot2 = 0, tot3 = 0;
        for (int i = l; i < m; ++ i) if (typ[i] == 2) AAA[tot1 ++] = val[i];
        for (int i = m; i < r; ++ i) if (typ[i] == 1) solve_tmp2[tot2 ++] = val[i];
        if (!tot1 || !tot2) return;
        Mul(0, 0, tot1);
        for (int i = 0; i < tot1 + 1; ++ i) solve_tmp1[i] = Mul_tmp[0][i];
        for (int i = tot1 + 1; i < tot1 * 3; ++ i) solve_tmp1[i] = 0;
        GGG(solve_tmp1, solve_tmp2, solve_tmp3, tot1 + 1, tot2);
        for (int i = m; i < r; ++ i) if (typ[i] == 1) ans[i] = 1ll * ans[i] * solve_tmp3[tot3 ++] % MOD;
    }
    int main()
    {
        int a, b, c, n;
        scanf("%d%d%d", &a, &b, &c); n = b + c;
        for (int i = 0; i < n; ++ i)
        {
            scanf("%d%d", &typ[i], &val[i]); ans[i] = 1;
    
            val[i] = ((val[i]) % MOD + MOD) % MOD;
        }
        solve(0, n);
        for (int i = 0; i < n; ++ i)
            if (typ[i] == 1) printf("%d
    ", ans[i]);
    }
    View Code

    令第(i-1)次询问到第(i)次询问之间的多项式之积为(A_i(x))

    那么显然有 (ans_i = (prod_{p=1}^{i} A_p(x)) mod (x - a_i))

    令(f_{l,r}=(prod_{p=1}^{l} A_p(x)) mod (prod_{p = l}^{r-1} (x - a_p)) )

    于是(ans_i = f_{i,i+1})

    注意到

    (f_{l,mid} = f_{l,r} mod (prod_{p = l}^{mid-1} (x - a_p)) )

    (f_{mid,r} =( f_{l,r} prod_{p=l+1}^{mid} A_p(x))  mod (prod_{p = mid}^{r-1} (x - a_p)) )

    (f_{1,q}=A_1(x) )

    预处理 需要用的 (x-a_i)的积 和 需要用的 (A_i(x) ) 的积(就是一个多项式分治乘法啦

    一次递归只需要跑一次多项式乘法和两次多项式取膜,多项式的度数是(O(len))的,因此一次递归的复杂度是(O(len log len))的

    (T(n) = 2 T(frac{n}{2})  + O(n log n)))

    最终复杂度(O(n log ^2 n))

    代码写的和上面的分析有些不同,所以有点萎(捂脸

    #pragma GCC optimize(2)
    #include <bits/stdc++.h>
    using namespace std;
    
    
    const int N = 1000000;
    const int MOD = 802160641;
    const int G = 11;
    int powi(int a, int b)
    {
        int c = 1;
        for (; b; b >>= 1, a = 1ll * a * a % MOD)
            if (b & 1) c = 1ll * c * a % MOD;
        return c;
    }
    void NTT(int A[], int n, int f)
    {
        for (int i = 0, j = 0; i < n; ++ i)
        {
            if (i > j) swap(A[i], A[j]);
            for (int l = n >> 1; (j ^= l) < l; l >>= 1);
        }
        for (int i = 2; i <= n; i <<= 1)
        {
            int w1 = powi(G, (MOD - 1) / i);
            if (f < 0) w1 = powi(w1, MOD - 2);
            for (int j = 0; j < n; j += i)
            {
                int w = 1;
                for (int k = j; k < j + (i >> 1); ++ k)
                {
                    int u = A[k], v = 1ll * A[k + (i >> 1)] * w % MOD;
                    A[k] = (u + v >= MOD? u + v - MOD: u + v);
                    A[k + (i >> 1)] = (u - v < 0? u - v + MOD: u - v);
                    w = 1ll * w * w1 % MOD;
                }
            }
        }
    
        int p = powi(n, MOD - 2);
        if (f < 0) for (int i = 0; i < n; ++ i) A[i] = 1ll * A[i] * p % MOD;
    }
    
    
    int Rev_tmp1[N], Rev_tmp2[N];
    void Rev(int A[], int G[], int n)
    {
        if (n == 1)
        {
            G[0] = powi(A[0], MOD - 2);
        }
        else
        {
            Rev(A, G, n / 2);
            for (int i = 0; i < n; ++ i) Rev_tmp1[i] = A[i];
            for (int i = n; i < (n << 1); ++ i) Rev_tmp1[i] = 0;
            for (int i = 0; i < (n >> 1); ++ i) Rev_tmp2[i] = G[i];
            for (int i = (n >> 1); i < (n << 1); ++ i) Rev_tmp2[i] = 0;
            NTT(Rev_tmp1, n << 1, 1);
            NTT(Rev_tmp2, n << 1, 1);
            for (int i = 0; i < (n << 1); ++ i) Rev_tmp1[i] = ((2 - 1ll * Rev_tmp1[i] * Rev_tmp2[i]) % MOD + MOD) * Rev_tmp2[i] % MOD;
            NTT(Rev_tmp1, n << 1, -1);
            for (int i = 0; i < n; ++ i) G[i] = Rev_tmp1[i];
        }
    }
    
    int Mod_tmp1[N], Mod_tmp2[N], Mod_tmp3[N], Mod_tmp4[N];
    void Mod(int A[], int B[], int D[], int n, int m)
    {
        while (B[m - 1] == 0) m --;
        if (n < m)
        {
            for (int i = 0; i < n; ++ i) D[i] = A[i];
            return;
        }
        int nn = 1;
        while (nn < (n - m + 1)) nn <<= 1;
        for (int i = 0; i < n; ++ i) Mod_tmp3[i] = A[i];
        for (int i = 0; i < m; ++ i) Mod_tmp4[i] = B[i];
        for (int i = 0, j = n - 1; i < j; ++ i, -- j) swap(Mod_tmp3[i], Mod_tmp3[j]);
        for (int i = 0, j = m - 1; i < j; ++ i, -- j) swap(Mod_tmp4[i], Mod_tmp4[j]);
        for (int i = m; i < nn; ++ i) Mod_tmp4[i] = 0;
        Rev(Mod_tmp4, Mod_tmp2, nn);
    
        for (int i = 0; i < n - m + 1; ++ i) Mod_tmp1[i] = Mod_tmp3[i];
        for (int i = n - m + 1; i < (nn << 1); ++ i) Mod_tmp1[i] = 0;
        for (int i = n - m + 1; i < (nn << 1); ++ i) Mod_tmp2[i] = 0;
        NTT(Mod_tmp1, nn << 1, 1);
        NTT(Mod_tmp2, nn << 1, 1);
        for (int i = 0; i < (nn << 1); ++ i) Mod_tmp1[i] = 1ll * Mod_tmp1[i] * Mod_tmp2[i] % MOD;
        NTT(Mod_tmp1, nn << 1, -1);
    
        while (nn < n) nn <<= 1;
        for (int i = 0, j = n - m; i < j; ++ i, -- j) swap(Mod_tmp1[i], Mod_tmp1[j]);
        for (int i = n - m + 1; i < (nn << 1); ++ i) Mod_tmp1[i] = 0;
        for (int i = 0; i < m; ++ i) Mod_tmp2[i] = B[i];
        for (int i = m; i < (nn << 1); ++ i) Mod_tmp2[i] = 0;
        NTT(Mod_tmp1, nn << 1, 1);
        NTT(Mod_tmp2, nn << 1, 1);
        for (int i = 0; i < (nn << 1); ++ i) Mod_tmp1[i] = 1ll * Mod_tmp1[i] * Mod_tmp2[i] % MOD;
        NTT(Mod_tmp1, nn << 1, -1);
    
        for (int i = 0; i < m - 1; ++ i) D[i] = (A[i] - Mod_tmp1[i] + MOD) % MOD;
    }
    
    int AAA[N], BBB[N];
    int Mul1[20][N], Mul2[20][N], Mul_tmp1[N], Mul_tmp2[N];
    void Mul(int Mul_tmp[][N], int x, int l, int r)
    {
        if (r - l == 1)
        {
            if (!BBB[l])
            {
                Mul_tmp[x][l * 2 + 1] = 1;
                Mul_tmp[x][l * 2] = AAA[l];
            }
            else
            {
                Mul_tmp[x][l * 2 + 1] = 0;
                Mul_tmp[x][l * 2] = 1;
            }
            return;
        }
        int m = (l + r) / 2;
        Mul(Mul_tmp, x + 1, l, m);
        Mul(Mul_tmp, x + 1, m, r);
        for (int i = 0; i < ((m - l) << 1); ++ i) Mul_tmp1[i] = Mul_tmp[x + 1][i + l * 2];
        for (int i = 0; i < ((r - m) << 1); ++ i) Mul_tmp2[i] = Mul_tmp[x + 1][i + m * 2];
        int nn = 1;
        while (nn < (r - l) * 2) nn <<= 1;
        for (int i = ((m - l) << 1); i < nn; ++ i) Mul_tmp1[i] = 0;
        for (int i = ((r - m) << 1); i < nn; ++ i) Mul_tmp2[i] = 0;
        NTT(Mul_tmp1, nn, 1);
        NTT(Mul_tmp2, nn, 1);
        for (int i = 0; i < nn; ++ i) Mul_tmp1[i] = 1ll * Mul_tmp1[i] * Mul_tmp2[i] % MOD;
        NTT(Mul_tmp1, nn, -1);
        for (int i = 0; i < ((r - l) << 1); ++ i) Mul_tmp[x][i + l * 2] = Mul_tmp1[i];
    }
    
    
    int cnt1[N], cnt2[N];
    int ans[N], typ[N], val[N];
    int solve_tmp[20][N], solve_tmp1[N], solve_tmp2[N];
    void solve(int x, int l, int r)
    {
        if (r - l == 1)
        {
            ans[l] = solve_tmp[x][l * 2];
            return;
        }
        if (cnt1[r] - cnt1[l] == 0) return;
        int m = (l + r) / 2;
        Mod(solve_tmp[x] + l * 2, Mul1[x + 1] + l * 2, solve_tmp[x + 1] + l * 2, (r - l) * 2, (m - l) * 2);
    
        int nn = 1;
        while (nn < (r - l) * 2) nn *= 2;
    
        for (int i = 0; i < (r - l) * 2; ++ i) solve_tmp1[i] = solve_tmp[x][i + l * 2];
        for (int i = (r - l) * 2; i < nn; ++ i) solve_tmp1[i] = 0;
        for (int i = 0; i < (m - l) * 2; ++ i) solve_tmp2[i] = Mul2[x + 1][i + l * 2];
        for (int i = (m - l) * 2; i < nn; ++ i) solve_tmp2[i] = 0;
        NTT(solve_tmp1, nn, 1);
        NTT(solve_tmp2, nn, 1);
        for (int i = 0; i < nn; ++ i) solve_tmp1[i] = 1ll * solve_tmp1[i] * solve_tmp2[i] % MOD;
        NTT(solve_tmp1, nn, -1);
        Mod(solve_tmp1, Mul1[x + 1] + m * 2, solve_tmp[x + 1] + m * 2, (r - l) * 2, (r - m) * 2);
    
        solve(x + 1, l, m);
        solve(x + 1, m, r);
    
    }
    
    namespace IO {
        const int SIZE=(int)(1e6);
        char buf[SIZE];
    
        FILE *in,*out;
        int cur;
    
        inline void init() {
            cur=SIZE;in=stdin;out=stdout;
        }
    
        inline char nextChar() {
            if(cur==SIZE) {
                fread(buf,SIZE,1,in);cur=0;
            } return buf[cur++];
        }
    
        inline int nextInt() {
            bool st=0,neg=0;
            char c;int num=0;
            while((c=nextChar())!=EOF) {
                if(c=='-') st=neg=1;
                else if(c>='0' && c<='9') {
                    st=1;num=num*10+c-'0';
                } else if(st) break;
            } if(neg) num=-num;
            return num;
        }
    
        inline void printChar(char c) {
            buf[cur++]=c;
            if(cur==SIZE) {
                fwrite(buf,SIZE,1,out);cur=0;
            }
        }
    
        inline void printInt(int x) {
            if(x<0) {
                printChar('-');printInt(-x);
                return;
            }
            if(x>=10) printInt(x/10);printChar('0'+x%10);
        }
    
        inline void close() {
            if(cur>0) fwrite(buf,cur,1,out);cur=0;
        }
    }
    
    int main()
    {
        using namespace IO;
        int a, b, c, n;
        init();
        a = nextInt();
        b = nextInt();
        c = nextInt();
        n = b + c;
        for (int i = 0; i < n; ++ i)
        {
            typ[i] = nextInt();
            val[i] = nextInt();
            ans[i] = 1;
            cnt1[i + 1] = cnt1[i] + (typ[i] == 1);
            cnt2[i + 1] = cnt2[i] + (typ[i] == 2);
            val[i] = ((val[i]) % MOD + MOD) % MOD;
        }
        for (int i = 0; i < n; ++ i) if (typ[i] == 2) BBB[i] = 0, AAA[i] = val[i]; else BBB[i] = 1;
        Mul(Mul2, 0, 0, n);
    
        for (int i = 0; i < n; ++ i) if (typ[i] == 1) BBB[i] = 0, AAA[i] = MOD - val[i]; else BBB[i] = 1;
        Mul(Mul1, 0, 0, n);
    
        solve_tmp[0][0] = 1;
        solve(0, 0, n);
    
        cur = 0;
        for (int i = 0; i < n; ++ i)
            if (typ[i] == 1) printInt(ans[i]), printChar('
    ');
        close();
    }
    View Code

    换了一个NTT板子,终于跑的比暴力快了QAQ

    学会了多项式技巧(划去 

  • 相关阅读:
    暑期测试训练3
    对于在线段树上修改整段区间的理解
    UVA 11090 判负圈问题
    ZOJ 2588 求割边问题
    POJ 1523 网络连通
    hdu 1163
    hdu 1703
    hdu 2577 模拟
    hdu 3836 强连通+缩点:加边构强连通
    hdu 2571
  • 原文地址:https://www.cnblogs.com/AwD-/p/6934418.html
Copyright © 2020-2023  润新知