zoukankan      html  css  js  c++  java
  • bzoj3992

    fft+数论

    抄了很多地方

    首先我们有个暴力dp,dp[i][j]表示到第i个数,乘积%m=j的方案数

    那么可以暴力转移。

    这个东西很明显不能矩阵快速幂,又不是卷积,但是我们可以转化

    还记得原根吗

    g^0...g^P-2 %P的余数各不相同,我们可以用指标代替数

    指标就是上面的幂

    设a的指标为ind[a]

    因为j=1->m-1,那么ind∈[0,m-1)可以表示[1,m)的所有数

    ind[a*b]=(ind[a]+ind[b])%(m-1)

    这样就可以构造卷积转移了,但是每次fft完要把i+m-1的东西加到i上,然后清零

    复杂度nmlogm

    卷积满足交换律和结合律

    那么我们用多项式快速幂就行了

    初始的ans是ans[0]=1.因为ind[1]=0

    复杂度mlogmlogn

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 32005, P = 1004535809;
    typedef long long ll;
    int t, m, x, s, n, k, g;
    ll a[N], b[N], ans[N], ind[N];
    ll power(ll x, ll t, ll P)
    {
        ll ret = 1;
        for(; t; t >>= 1, x = x * x % P) if(t & 1) ret = ret * x % P;
        return ret;
    }
    void ntt(ll *a, int f)
    {
        for(int i = 0; i < n; ++i)
        {
            int t = 0;
            for(int j = 0; j < k; ++j) if(i >> j & 1) t |= 1 << (k - j - 1);
            if(i < t) swap(a[i], a[t]);
        }
        for(int l = 2; l <= n; l <<= 1)
        {
            ll w = power(3, f == 1 ? (P - 1) / l : P - 1 - (P - 1) / l, P);
            int m = l >> 1;
            for(int i = 0; i < n; i += l) 
            {
                ll t = 1;
                for(int k = 0; k < m; ++k, t = t * w % P)
                {
                    ll x = a[i + k], y = t * a[i + m + k];
                    a[i + k] = (x + y) % P;
                    a[i + m + k] = ((x - y) % P + P) % P;
                }
            }        
        }
        if(f == -1)
        {
            ll inv = power(n, P - 2, P);
            for(int i = 0; i < n; ++i) a[i] = a[i] * inv % P;
        }
    }
    void sqr(ll *a)
    {
        ntt(a, 1);
        for(int i = 0; i < n; ++i) a[i] = a[i] * a[i] % P;
        ntt(a, - 1);
        for(int i = 0; i < m - 1; ++i) a[i] = (a[i] + a[i + m - 1]) % P, a[i + m - 1] = 0;
    }
    ll get_(int m)
    {
        if(m == 2) return 1;
        for(ll g = 2; g < m; ++g)
        {  
            bool flag =  1;
            ll lim = sqrt(m);
            for(ll i = 2; i <= lim; ++i) if((m - 1) % i == 0)
            {
                if(power(g, (m - 1) / i, m) == 1)
                {
                    flag = false;
                    break;
                }
            }
            if(flag) return g;
        }
    }
    int main()
    {
        scanf("%d%d%d%d", &t, &m, &x, &s);
        n = 1;
        k = 0;
        while(n <= 2 * m) n <<= 1, ++k;
        g = get_(m);
        ll A = 1;
        for(int i = 0; i < m - 1; ++i, A = A * g % m) ind[A] = i; 
        ans[0] = 1; 
        for(int i = 1; i <= s; ++i) 
        {
            int x;
            scanf("%d", &x);
            if(x) a[ind[x]] = 1;
        }
        for(; t; t >>= 1, sqr(a)) if(t & 1) 
        {
            for(int i = 0; i < n; ++i) b[i] = a[i];
            ntt(b, 1);
            ntt(ans, 1);
            for(int i = 0; i < n; ++i) ans[i] = ans[i] * b[i] % P;
            ntt(ans, -1);
            for(int i = 0; i < m - 1; ++i) ans[i] = (ans[i] + ans[i + m - 1]) % P, ans[i + m - 1] = 0;
        }
        printf("%lld
    ", ans[ind[x]]);
        return 0;
    }
    View Code
  • 相关阅读:
    jQuery 回到顶部
    c# 获取客户端ip
    JS 新浪API获取IP归属地
    c#抓取网站数据
    ECLIPSE最常用快捷键排名
    BinarySearchTree示例——C++模板实现
    SICP 找零钱问题背后的思考
    关于解引用*和箭头操作符->的重载
    traits技法小计
    最大和子序列问题
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8058656.html
Copyright © 2011-2022 走看看