zoukankan      html  css  js  c++  java
  • bzoj4589

    fwt

    原理并不知道

    nim游戏石子异或和=0后手赢

    那么也就是求a[1]^a[2]^...^a[n]=0的方案数

    这个和bzoj3992一样可以dp

    dp[i][j]表示前i个数异或和为j的方案数 dp[0][0] = 1

    dp[i][j] = dp[i - 1][k] * a[p] p ^ k = j a[p] = 0 / 1 表示有没有p这个数

    这个东西也不能矩阵快速幂 

    但是我们有一个叫fwt的东西

    能够求c = a @ b @是一种运算 -----> c[i] = a[j] * b[k] i = j ^ k

    那么每次转移就是fwt了

    由于转移的形式一样 那么就可以快速幂 并且由于fwt运算并不会向fft那样下标多出来一些东西 也就不用算循环卷积

    直接fwt后每个数pow一下 再ifwt就行了

    复杂度O(n log n + n log m)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 70005;
    const ll P = 1000000007;
    int n, m, len;
    ll inv;
    ll a[N];
    int p[N], mark[N];
    ll power(ll x, ll t) 
    {
        ll ret = 1;
        for(; t; t >>= 1, x = x * x % P) if(t & 1) ret = ret * x % P;
        return ret;
    }
    void fwt(ll *a, int n) 
    {
        for(int l = 2; l <= n; l <<= 1)
        { 
            int m = l >> 1;
            for(int i = 0; i < n; i += l) 
                for(int k = 0; k < (l >> 1); ++k)
                {
                    ll x = a[i + k], y = a[i + k + m];
                    a[i + k] = (x + y) % P;
                    a[i + k + m] = ((x - y) % P + P) % P;
                }
        }
    }
    void ifwt(ll *a, int n)
    {
        for(int l = n; l >= 2; l >>= 1)
        {
            int m = l >> 1;
            for(int i = 0; i < n; i += l)
                for(int k = 0; k < m; ++k)
                {
                    ll x = a[i + k], y = a[i + m + k];
                    a[i + k] = (x + y) % P * inv % P;
                    a[i + m + k] = ((x - y) % P + P) % P * inv % P;
                }
        }
    }
    int main()
    {
        inv = power(2, P - 2);
        for(int i = 2; i <= 50000; ++i) 
        {
            if(!mark[i]) p[++p[0]] = i;
            for(int j = 1; j <= p[0] && i * p[j] <= 50000; ++j) 
            {
                mark[i * p[j]] = 1;
                if(i % p[j] == 0) break;
            }
        }
        while(scanf("%d%d", &n, &m) != EOF) 
        {
            memset(a, 0, sizeof(a));
            for(int i = 1; i <= p[0] && p[i] <= m; ++i) a[p[i]] = 1;
            for(len = 1; len <= m; len <<= 1);
            fwt(a, len);
            for(int i = 0; i < len; ++i) a[i] = power(a[i], n);
            ifwt(a, len);
            printf("%lld
    ", a[0]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    iOS开发App上传的三大步骤
    iOS开发关于AppStore程序的上传流程
    AFNetworking 3.0x版本最新特性
    iOS开发中两个不错的宏定义
    iOS开发中NSDate时间戳的转换--
    HDU 2844 Coins 多重背包
    poj 1888 Crossword Answers 模拟题
    杭电oj 1069 Monkey and Banana 最长递增子序列
    郑轻校赛题目 问题 G: 多少个0
    HDU 2571 命运
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8284565.html
Copyright © 2011-2022 走看看