CF914G Sum the Fibonacci FWT、子集卷积

传送门



一道良心的练习FWT和子集卷积的板子……

具体来说就是先把所有满足\(s_a \& s_b = 0\)的\(s_a \mid s_b\)的值用子集卷积算出来,将所有\(s_a \oplus s_b\)用xor卷积算出来,把斐波那契数代进去,然后将三个数组and卷积,最后取\(2^i (i \in Z)\)的位置的答案的和

#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;

int read(){
    int a = 0; char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}

const int _ = (1 << 17) + 3 , MOD = 1e9 + 7;
#define lowbit(x) (x & (-x))
int fib[_] , arr[_] , cnt1[_] , Or[18][_] , ansOr[_] , tmp[_] , And[_] , Xor[_] , N;

void orFWT(int *arr , long long tp){
    for(int i = 0 ; i < 17 ; ++i)
        for(int j = 0 ; j < 1 << 17 ; j += 1 << (i + 1))
            for(int k = 0 ; k < 1 << i ; ++k)
                arr[(1 << i) + j + k] = (arr[(1 << i) + j + k] + tp * arr[j + k] + MOD) % MOD;
}

void andFWT(int *arr , long long tp){
    for(int i = 0 ; i < 17 ; ++i)
        for(int j = 0 ; j < 1 << 17 ; j += 1 << (i + 1))
            for(int k = 0 ; k < 1 << i ; ++k)
                arr[j + k] = (arr[j + k] + tp * arr[(1 << i) + j + k] + MOD) % MOD;
}

void xorFWT(int *arr , long long tp){
    for(int i = 0 ; i < 17 ; ++i)
        for(int j = 0 ; j < 1 << 17 ; j += 1 << (i + 1))
            for(int k = 0 ; k < 1 << i ; ++k){
                int x = arr[j + k] , y = arr[(1 << i) + j + k];
                arr[j + k] = (x + y) % MOD;
                arr[(1 << i) + j + k] = (x - y + MOD) % MOD;
                if(tp == -1){
                    if(arr[j + k] & 1) arr[j + k] += MOD;
                    arr[j + k] >>= 1;
                    if(arr[(1 << i) + j + k] & 1) arr[(1 << i) + j + k] += MOD;
                    arr[(1 << i) + j + k] >>= 1;
                }
            }
}

void init(){
    for(int i = 1 ; i < 1 << 17 ; ++i)
        cnt1[i] = cnt1[i - lowbit(i)] + 1;
    fib[1] = 1;
    for(int i = 2 ; i < 1 << 17 ; ++i)
        fib[i] = (fib[i - 1] + fib[i - 2]) % MOD;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    init();
    N = read();
    for(int i = 1 ; i <= N ; ++i){
        int p = read();
        ++arr[p]; ++Or[cnt1[p]][p];
    }
    memcpy(And , arr , sizeof(arr)); memcpy(Xor , arr , sizeof(arr));
    for(int i = 0 ; i <= 17 ; ++i)
        orFWT(Or[i] , 1);
    for(int i = 0 ; i <= 17 ; ++i){
        memset(tmp , 0 , sizeof(tmp));
        for(int j = 0 ; j <= i ; ++j)
            for(int k = 0 ; k < 1 << 17 ; ++k)
                tmp[k] = (tmp[k] + 1ll * Or[j][k] * Or[i - j][k]) % MOD;
        orFWT(tmp , -1);
        for(int k = 0 ; k < 1 << 17 ; ++k)
            if(cnt1[k] == i)
                ansOr[k] = tmp[k];
    }
    xorFWT(Xor , 1);
    for(int i = 0 ; i < 1 << 17 ; ++i)
        Xor[i] = 1ll * Xor[i] * Xor[i] % MOD;
    xorFWT(Xor , -1);
    for(int i = 0 ; i < 1 << 17 ; ++i){
        ansOr[i] = 1ll * ansOr[i] * fib[i] % MOD;
        And[i] = 1ll * And[i] * fib[i] % MOD;
        Xor[i] = 1ll * Xor[i] * fib[i] % MOD;
    }
    andFWT(ansOr , 1); andFWT(And , 1); andFWT(Xor , 1);
    for(int i = 0 ; i < 1 << 17 ; ++i)
        And[i] = 1ll * ansOr[i] * And[i] % MOD * Xor[i] % MOD;
    andFWT(And , -1);
    int ans = 0;
    for(int i = 1 ; i < 1 << 17 ; i <<= 1)
        ans = (ans + And[i]) % MOD;
    cout << ans;
    return 0;
}

原文地址:https://www.cnblogs.com/Itst/p/10779302.html

时间: 2024-11-10 12:52:18

CF914G Sum the Fibonacci FWT、子集卷积的相关文章

CF 914 G Sum the Fibonacci —— 子集卷积,FWT

题目:http://codeforces.com/contest/914/problem/G 其实就是把各种都用子集卷积和FWT卷起来算即可: 注意乘 Fibonacci 数组的位置: 子集卷积时不能一边做一边更新卷积的数组! 代码如下: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int rd() { int ret=

【CF914G】Sum the Fibonacci 快速??变换模板

[CF914G]Sum the Fibonacci 题解:给你一个长度为n的数组s.定义五元组(a,b,c,d,e)是合法的当且仅当: 1. $1\le a,b,c,d,e\le n$2. $(s_a|s_b) \& s_c \& (s_d $^$ s_e)=2^i$,i是某个整数3. $s_a \& s_b=0$ 求$\sum f(s_a|s_b) * f(s_c) * f(s_d $^$ s_e)$,f是斐波那契数列,对于所有合法的五元组(a,b,c,d,e).答案模$10^9

hdu 6057 Kanade&#39;s convolution(子集卷积)

题解: 然后就是接下来如何fwt 也就是如何处理bit(x) - bit(y) = bit(k)这个条件. 其实就是子集卷积. 把bit(x)和bit(y)划分成两个集合,然后就是子集卷积的形式. 这里设两个新的数组 A[bit(y)][y], B[bit(x)][x],代表拆出来的相应数组 然后对这两个数组做fwt,得到其点值表示,然后直接在外层枚举x和y的大小然后做卷积即可. 这样说可能很抽象,其实贴出代码就很清楚了 #include <iostream> #include <vec

Future Failure CodeForces - 838C (博弈论,子集卷积)

大意: 两人轮流操作一个长$n$, 只含前$k$种小写字母的串, 每次操作删除一个字符或者将整个串重排, 每次操作后得到的串不能和之前出现过的串相同, 求多少种串能使先手必胜. 找下规律发现$n$为奇数必胜, 否则假设$a_i$为字符$i$出现次数, 如果$\frac{n!}{a_1!a_2!...a_k!}$为奇数则必败 $n!$中$2$的幂次为n-__builtin_popcount(n) 所以必败就等价于$a_1+...+a_n=a_1|...|a_n$ 设$f_{i,j}$表示前$i$个

FMT 和 子集卷积

FMT 和 子集卷积 FMT 给定数列 $ a_{0\dots 2^{k}-1} $ 求 $ b $ 满足 $ b_{s} = \sum_{i\in s} a_i $ 实现方法很简单, for( i in 0..n-1 ) for( j in 0..2^n-1) if( j & ( 1 << i ) ) a[j] += a[j ^ ( 1 << i )] 然后称为 $ B = FMT(A) $ ,快速莫比乌斯变换 想要还原也很简单,把代码反着写: for( i in n-1

FWT,FST入门

0.目录 目录 0.目录 1.什么是 FWT 2. FWT 怎么做 2.1. 或卷积 2.2.与卷积 2.3.异或卷积 2.4.例题 3. FST 3.1. FST 怎么做 3.2.例题 1.什么是 FWT ?? FWT 全称为 " 快速沃尔什变换: Fast Walsh Transform " .可以用于解决位运算卷积的问题. ??什么叫位运算卷积呢?我们考虑普通的卷积,即: \[C_k=\sum_{i+j=k}A_iB_j \] ??位运算卷积就是下标为位运算的卷积(此处与和或用

Luogu4221 WC2018州区划分(状压dp+FWT)

合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方案的满意度之和,枚举子集转移,则有f[S]=Σg[S']*f[S^S']*(sum[S']/sum[S])p (S'?S),其中g[S]为S集合是否合法,sum[S]为S集合人口数之和.复杂度O(3n).这个式子非常显然,就这么送了50分.p这么小显得非常奇怪但也没有任何卵用. 考虑优化.转移方程写

FWT 等总结

目录 与卷积: 代码: 或卷积: 代码: 异或卷积: 代码: FWT可以解决位运算卷积问题. 即\(h(i)=\sum\limits_{j⊕k=i} f(j)*g(k)\),其中"⊕"表示位运算. 与卷积: 定义\(f\)到\(F\)的变换:\(F(i)=\sum\limits_{j\&i==i}^{ }f(j)\). 这样,若\(h(i)=\sum\limits_{j and k=i} f(j)*g(k)\),则\(H(i)=F(i)*G(i)\). 变换方法:就是按照长度为

集合并卷积的三种求法

也许更好的阅读体验 本文主要内容是对武汉市第二中学吕凯风同学的论文<集合幂级数的性质与应用及其快速算法>的理解 定义 集合幂级数 为了更方便的研究集合的卷积,引入集合幂级数的概念 集合幂级数也是形式幂级数的一种,只是集合的一种表现形式,无需考虑收敛或发散的含义 定义一个集合 \(S\) 的集合幂级数为 \(f\) ,那么我们就可以把集合 \(S\) 表示为如下形式 \(\begin{aligned}f=\sum _{T\subseteq S}f_{T}\cdot x^{T}\end{align