• HDU 6088


    思路和任意模数FFT模板都来自 这里

    看了一晚上那篇《再探快速傅里叶变换》还是懵得不行,可能水平还没到- -

    只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太差了...

    具体推导大概这样就可以了:

    /*
    HDU 6088 - Rikka with Rock-paper-scissors [ 任意模数FFT,数论 ]  |  2017 Multi-University Training Contest 5
    题意:
    	计算 3^n * ∑ [0<=i+j<=n] C(n, i) * C(n-i, j) * GCD(i,j)
    	N <= 1e5
    分析:
    	利用 n = ∑ [d|n] φ(d)
    	化得:
    		3^n * ∑[1<=d<=n] d ∑ [0<=i+j<=n/d] C(n,i*d) * C(n-i*d, j*d)
    	之后枚举 d  (以下略写 *d )
    		C(n,i*d) * C(n-i*d, j*d)
    		= n! * 1/(i!) * 1/(j!) * 1/(n-i-j)!
    			维护 f(i) = 1/i! 的卷积 g(k) = ∑ [i+j == k] * f(i) * f(j)
    		原式 = ∑[1<=i<=m] n! * g(k) * 1/(n-k)!
    	由于 gcd(0, 0) == 0
    	所以特判卷积的 g(0) 项不用加上
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define MOD mod
    #define upmo(a,b) (((a)=((a)+(b))%MOD)<0?(a)+=MOD:(a))
    typedef long long LL;
    typedef double db;
    const int N = 1e5+5;
    int t, n;
    LL inv[N], F[N], Finv[N], phi[N];
    LL MOD;
    namespace FFT_MO
    {
        const int FFT_MAXN = 1<<18;
        const db PI = 4*atan(1.0);
        struct cp
        {
            db a, b;
            cp(db a_ = 0, db b_ = 0) {
                a = a_, b = b_;
            }
            cp operator + (const cp& rhs) const {
                return cp(a+rhs.a, b+rhs.b);
            }
            cp operator - (const cp& rhs) const {
                return cp(a-rhs.a, b-rhs.b);
            }
            cp operator * (const cp& rhs) const {
                return cp(a*rhs.a-b*rhs.b, a*rhs.b + b*rhs.a);
            }
            cp operator !() const{
                return cp(a, -b);
            }
        }nw[FFT_MAXN+1], f[FFT_MAXN], g[FFT_MAXN], t[FFT_MAXN];
        int bitrev[FFT_MAXN];
        void fft_init()
        {
            int L = 0; while ((1<<L) != FFT_MAXN) L++;
            for (int i = 1; i < FFT_MAXN; i++)
                bitrev[i] = bitrev[i>>1]>>1 | ((i&1)<<(L-1));
            for (int i = 0; i <= FFT_MAXN; i++)
                nw[i] = cp((db)cosl(2*PI/FFT_MAXN*i), (db)sinl(2*PI/FFT_MAXN*i));
        }
        void dft(cp *a, int n, int flag = 1)
        {
            int d = 0; while ((1<<d)*n != FFT_MAXN) d++;
            for (int i = 0; i < n; i++) if (i < (bitrev[i]>>d))
                swap(a[i], a[bitrev[i]>>d]);
            for (int l = 2; l <= n; l <<= 1)
            {
                int del = FFT_MAXN/l*flag;
                for (int i = 0; i < n; i += l)
                {
                    cp *le = a+i, *ri = a+i+(l>>1);
                    cp *w = flag==1 ? nw : nw+FFT_MAXN;
                    for (int k = 0; k < (l>>1); k++)
                    {
                        cp ne = *ri * *w;
                        *ri = *le - ne, *le = *le+ne;
                        le++, ri++, w += del;
                    }
                }
            }
            if (flag != 1) for (int i = 0; i < n; i++) a[i].a /= n, a[i].b /= n;
        }
        void convo(LL *a, int n, LL *b, int m, LL *c)
        {
            for (int i = 0; i <= n+m; i++) c[i] = 0;
            int N = 2; while (N <= n+m) N <<= 1;
            for (int i = 0; i < N; i++)
            {
                LL aa = i <= n ? a[i] : 0, bb = i <= m ? b[i] : 0;
                aa %= MOD, bb %= MOD;
                f[i] = cp(db(aa>>15), db(aa&32767));
                g[i] = cp(db(bb>>15), db(bb&32767));
            }
            dft(f, N), dft(g, N);
            for (int i = 0; i < N; i++)
            {
                int j = i ? N-i : 0;
                t[i] = ((f[i]+!f[j])*(!g[j]-g[i]) + (!f[j]-f[i])*(g[i]+!g[j])) * cp(0, 0.25);
            }
            dft(t, N, -1);
            for (int i = 0; i <= n+m; i++) upmo(c[i], (LL(t[i].a+0.5))%MOD<<15);
            for (int i = 0; i < N; i++)
            {
                int j = i? N-i : 0;
                t[i] = (!f[j]-f[i])*(!g[j]-g[i])*cp(-0.25,0) + cp(0,0.25)*(f[i]+!f[j])*(g[i]+!g[j]);
            }
            dft(t, N, -1);
            for (int i = 0; i <= n+m; i++)
                upmo(c[i], LL(t[i].a+0.5)+(LL(t[i].b+0.5)%MOD<<30));
        }
    }
    LL a[1<<18|1], b[1<<18|1], c[1<<18|1];
    LL PowMod(LL a, LL m)
    {
        a %= MOD;
        LL ret = 1;
        while (m) {
            if (m&1) ret = ret * a % MOD;
            m >>= 1;
            a = a*a % MOD;
        }
        return ret;
    }
    void GetEuler()
    {
        memset(phi, 0, sizeof(phi));
        phi[1] = 1;
        for (int i = 2; i < N; i++)
            if (!phi[i])
                for (int j = i; j < N; j += i)
                {
                    if (!phi[j]) phi[j] = j;
                    phi[j] = phi[j] / i * (i-1);
                }
    }
    void init(int n) {
        inv[1] = 1;
        for (int i = 2; i <= n; i++)
            inv[i] = (MOD - MOD/i) *inv[MOD % i] % MOD;
        F[0] = Finv[0] = 1;
        for (int i = 1; i <= n; i++) {
            F[i] = F[i-1] * i % MOD;
            Finv[i] = Finv[i-1] * inv[i] % MOD;
        }
    }
    int main()
    {
        GetEuler();
        scanf("%d", &t);
        while (t--)
        {
            scanf("%d%lld", &n, &MOD);
            init(n);
            FFT_MO::fft_init();
            LL ans = 0;
            for (int d = 1; d <= n; d++)
            {
                int m = n/d;
                for (int i = 0; i <= m; i++) b[i] = a[i] = Finv[i*d];
                FFT_MO::convo(a, m, b, m, c);
                for (int i = 0; i <= m; i++) c[i] = c[i] * Finv[n-i*d] % MOD;
                LL sum = 0;
                for (int i = 1; i <= m; i++) sum = (sum + c[i]) % MOD;
                ans = (ans + sum * phi[d]) % MOD;
            }
            ans = ans * F[n] % MOD * PowMod(3, n) % MOD;
            printf("%lld
    ", ans);
        }
    }
    

      

  • 相关阅读:
    NHibernate学习之二
    ETL学习之四:SQL Server Integration Services入门
    NHibernate学习之五:三种常见的配置方法。
    ORACLE执行计划入门
    C# default關鍵字
    WordPress Mail On Update插件跨站请求伪造漏洞
    WordPress Colormix主题多个安全漏洞
    nginx 'ngx_http_parse.c'栈缓冲区溢出漏洞
    Apache HTTP Server日志内终端转义序列命令注入漏洞
    WordPress wpFileManager插件‘path’参数任意文件下载漏洞
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/7354961.html
Copyright © 2020-2023  润新知