6467. 【GDOI2020模拟02.09】西行寺无余涅槃(FWT的性质)

题目描述

题解

吼题

推荐博客:https://www.cnblogs.com/jz-597/p/12300760.html

最暴力的做法是把n个2^m的FWT乘起来,这样显然不行

先把pi,1~k异或上pi,1,把pi,1变为0,最后再把pi,1异或回去

考虑FWT(xor)的本质,tr(A)=(tr(A1)+tr(A2),tr(A1)-tr(A2)),倒着做可以发现只有变换的u和u+2^k(u&2^k=0)只有u+2^k--->u+2^k这一操作时才需要变号

要求FWT(A)i,就等于把j=0~N-1(N表示FWT的大小,注意大小写)通过不断变号最后加到位置i,变换的实质是把j从后往前一位位变成i

根据上面的结论,只有i和j在当前位都为1时才会变号

记|x|表示x中1的位数,所以\(FWT(A)_i=∑_{j=0}^{N-1}{(-1)^{|i\&j|}A_j}\)



n个FWT的每一位只有2^(k-1)种取值(a1必然为正,x&0=0),因此第\(I\)(注意大小写)位的乘积可以表示成\(\prod\)每种取值^出现次数

考虑求出每个\(I\)的2^(k-1)种乘积的出现次数,然后求出FWT的积,最后IFWT还原出答案

然而直接求出现次数不好求,考虑用FWT(第二种,不同于上面的)来搞

因为FWT实质上是每一位乘上系数再求和,所以可以把每一位分开求

暴力FWT时在pi,2位置上加上a2,则FWT后位置\(I\)的a2系数为\((-1)^{|I\&p_{i,2}|}\)

在pi,2上+1,FWT后可以得到piFWT后第\(I\)位的a2系数

若把i=1~n的pi,2都+1,FWT后得到的则是p1~nFWT后第\(I\)位的a2系数之和,即第\(I\)位所乘的数中a2为正的个数-a2为负的个数

如图,求得的东西就是第\(I\)位中a2的系数之和,等于正数-负数个数

假设k=3,设x0=a1+a2+a3,x1=a1-a2+a3,x2=a1+a2-a3,x3=a1-a2-a3

那么求得的a2正-a2负=x0+x2-x1-x3

同理,在pi,3处+1可得x0+x1-x2-x3

加上最初的x0+x1+x2+x3=n,一共有3条方程4个未知数,无法解

考虑在pi,2⊕pi,3的位置+1,看看得到什么

首先有一条式子:a&(b⊕c)=(a⊕b)&(a⊕c)

证明:若a的某一位为0,则左右两边都为0,否则都为b⊕c

那么FWT后第\(I\)位为\((-1)^{|I\&(p_{i,2} \bigoplus p_{i,3})|}\),由上可知等于\((-1)^{|I\&(p_{i,2})|}*(-1)^{|I\&(p_{i,3})|}\)

把正看成0,负看成1,乘看成异或,则符号满足位运算的性质,这个东西就是a2与a3的符号的异或,求得的是(异或为正-异或为负)

所以同上可得x0-x1-x2+x3

推广一下,一共有2^(k-1)个未知数,枚举子集异或共有2^(k-1)-1条方程,加上∑xi=n共2^(k-1)条,可以高斯消元

但是消元太慢了,观察一下n=4时FWT的结果

{a,b,c,d}-->{a+b+c+d,a-b+c-d,a+b-c-d,a-b-c+d}

和x的关系完全一致,所以把求得的方程按照顺序(-1看成1,2~k对应二进制从低到高)排好后IFWT(第三种,不同于之前的两种)即可

证明见https://blog.csdn.net/zxyoi_dreamer/article/details/104188934

∑xi=n不必特判,因为当第0位为n时FWT后每一位都为n

注意三种FWT/IFWT的大小与含义差别

code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 998244353
#define two 499122177
#define file
using namespace std;

int P[10]={0,1,2,4,8,16,32,64,128,256};
int p[1000001][10];
long long a[21];
long long A[1048576];
long long b[1048576];
long long c[1048576];
long long p2[1048576];
long long sum[512];
int n,m,m2,K,k2,i,j,k,l,S;

long long qpower(long long a,int b)
{
    long long ans=1;

    while (b)
    {
        if (b&1)
        ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }

    return ans;
}

void fwt(int st,long long *a,int N,int len,int type)
{
    int i,j,k,l,s1=2,s2=1,S=N;
    long long u,v;

    fo(i,1,len)
    {
        S/=2;
        fo(j,0,S-1)
        {
            fo(k,0,s2-1)
            {
                u=a[st+j*s1+k];
                v=a[st+j*s1+k+s2];

                if (type==1)
                a[st+j*s1+k]=(u+v)%mod,a[st+j*s1+k+s2]=(u-v)%mod;
                else
                a[st+j*s1+k]=(u+v)*two%mod,a[st+j*s1+k+s2]=(u-v)*two%mod;
            }
        }
        s1*=2,s2*=2;
    }
}

void dg(int t,int s1,long long s2)
{
    int i;

    if (t>K)
    {
        memset(c,0,8*m2);
        sum[s1]=s2;

        fo(i,1,n)
        ++c[p2[i]];
        fwt(0,c,m2,m,1);

        fo(i,0,m2-1)
        b[i*k2+s1]=c[i];
        return;
    }

    dg(t+1,s1,(s2+a[t])%mod);

    fo(i,1,n) p2[i]^=p[i][t];
    dg(t+1,s1|P[t-1],(s2-a[t])%mod);
    fo(i,1,n) p2[i]^=p[i][t];
}

int main()
{
    freopen("yuyuko.in","r",stdin);
    #ifdef file
    freopen("yuyuko.out","w",stdout);
    #endif

    scanf("%d%d%d",&n,&m,&K);m2=qpower(2,m),k2=qpower(2,K-1); //2^(k-1)
    fo(i,1,K)
    scanf("%lld",&a[i]);
    fo(i,1,n)
    {
        fo(j,1,K)
        scanf("%d",&p[i][j]);

        S^=p[i][1];
        fd(j,K,1)
        p[i][j]^=p[i][1];
    }

//  ---

    dg(2,0,a[1]); //1

    fo(i,0,m2-1) //2
    {
        fwt(i*k2,b,k2,K-1,-1);

        A[i]=1;
        fo(j,0,k2-1)
        A[i]=A[i]*qpower(sum[j],b[i*k2+j])%mod;
    }

//  ---

    fwt(0,A,m2,m,-1);
    fo(i,0,m2-1)
    printf("%lld ",(A[i^S]+mod)%mod);
    printf("\n");

    fclose(stdin);
    fclose(stdout);

    return 0;
}

原文地址:https://www.cnblogs.com/gmh77/p/12318077.html

时间: 2024-08-30 14:42:55

6467. 【GDOI2020模拟02.09】西行寺无余涅槃(FWT的性质)的相关文章

6476. 【GDOI2020模拟02.19】A

题目 题目比较简洁,就不复述了. 思考历程 这让我联想到了不久之前在CF上做的一道题. 但这两道题的差别是很大的,共同点并不是很多. 直接套那题的方法在这题中也顶多拿个40分. 考虑探索新大陆,然而没有成功-- 感觉这题的暴力不好打,最终也没有打部分分-- (所以说我在这题上耗费了1h) 正解 正解的思路比较清奇. 不用说也知道这题要容斥一下,我比赛时一直在想着保留上界,然而正解是保留下界. 如果想到的话也挺显然的,首先用最终的值减去下界,接下来用生成函数去考虑,就相当于\(\frac{1}{(

6461. 【GDOI2020模拟02.05】生成树(矩阵树及其扩展、二维拉格朗日插值)

题目描述 给定一张 N 个点,M 条边的无向图,边有红.绿.蓝三种颜色,分别用 1,2,3 表示. 求这张图有多少生成树,满足绿色边数量不超过 x,蓝色边数量不超过 y,答案对10^9 + 7 取模. 1 ≤ N ≤ 40,1 ≤ M ≤ 10^5,1 ≤ ci ≤ 3 行列式 定义矩阵A的行列式det(A)或|A| \(|A|=\sum_{排列p}{(-1)^{p的逆序对个数}\prod{A_{i,p[i]}}}\) 行列式的性质 (\(A\)的转置矩阵\(A^T\):把\(A\)的行列互换)

6476. 【GDOI2020模拟02.19】A(范德蒙恒等式)

题目描述 题解 镇♂男则反 容斥下界,上界开到大概505位,数位dp最终的和V 设边界(要大于边界)之和为S,那么答案为C(V-S-1,n-1) 根据范德蒙恒等式,C(n+m,k)=∑C(n,i)*C(m,k-i) 如果nm都是正数很好证明,把n+m分成n和m两部分,枚举n部分选择个数组合一下 这个式子其实可以拓展到负数,证明要用生成函数 关于n为负数的组合数:\(C(n,m)=n^{\underline{m}}/m!\),其实和正数时是一样的 (注意这只是为了计算范德蒙恒等式而扩展的,在一般情

2019模拟赛09场解题报告

目录 2019模拟赛09场解题报告 目录la~~ 题一:瞬间移动 题二:食物订购 题三:马蹄印 题四:景观美化 2019模拟赛09场解题报告 标签(空格分隔): 解题报告 Forever_chen 2019.8.20 目录la~~ 题一:瞬间移动 [题面] 有一天,暮光闪闪突然对如何将一个整数序列a1,a2,...,an排序为一个不下降序列起了兴趣.身为一只年轻独角兽的她,只能进行一种叫做"单元转换"(unit shift)的操作.换句话说,她可以将序列的最后一个元素移动到它的起始位置

6442. 【GDOI2020模拟01.18】钩子

题目描述 Description Input Output Sample Input Sample Input1 3 1000000007 Sample Input2 4 1000000007 Sample Output Sample Output1 0 1 0 500000004 0 500000004 500000004 0 500000004 Sample Output2 0 500000004 500000004 0 333333336 166666668 166666668 33333

jzoj2701 【GDKOI2012模拟02.01】矩阵

传送门:https://jzoj.net/senior/#main/show/2701 [题目大意] 给出矩阵A,求矩阵B,使得 最小,矩阵B每个元素在[L,R]内 n<=200,1<=Aij,L,R<=1000, L<=R [题解] 我们二分答案x,然后对行列建点,每行向每列连[L,R]的边,然后S向每行连[max(S[i]-x), S[i]+x]的边,每列向T连[max(T[i]-x), T[i]+x]的边,判断是否有可行流即可. 其中S[i]表示A中第i行的和,T[i]表示A

NOIP模拟 9.09

我太弱辣,三道题都爆零啦 果实计数 (count.pas/.c/.cpp) 时间限制:1s,空间限制32MB 题目描述: 淘淘家有棵奇怪的苹果树,这棵树共有n+1层,标号为0~n.这棵树第0层只有一个节点,为根节点.已知这棵树为b叉树,且保证是一颗满b叉树.如图为一颗满3叉树. 现在,该树第n层的每个节点上都结出了一个苹果,淘淘想知道共结了多少苹果.由于数量可能很大,答案要求输出mod k后的结果. 输入描述: 给出第1层的节点数b和层数n和k. 输出描述: 输出苹果数mod k后的结果. 样例

jzoj2700 【GDKOI2012模拟02.01】数字

传送门:https://jzoj.net/senior/#main/show/2700 [题目大意] 令n为正整数,S(n)为n的各位数字之和,令 小Z喜欢的数一定能表示成 x * D(x) 这种形式. 小D也是个开朗的人,他知道QQ号码是随出来的.那么,他想知道在区间[L, R]中,他喜欢的数出现了多少次呢? 多组数据. 1<=T<=5, 1<=L<=R<=10^18 [题解] 打一个表就知道D(n)=((n-1) mod 9) + 1 然后我们如果有k * D(k) =

内部类(转载http://www.cnblogs.com/devinzhang/archive/2012/02/09/2344059.html)

Java内部类总结 Java内部类其实在J2EE编程中使用较少,不过在窗口应用编程中特别常见,主要用来事件的处理.其实,做非GUI编程,内部类完全可以不用. 内部类的声明.访问控制等于外部类有所不同,要灵活使用内部类来编写程序,还是有相当难度的,Java发明了这种难懂的玩意儿,在其他语言中是没有的,但是在Java中,内部类也相当的重要,尤其做GUI开发时候,事件的响应处理全靠内部类了. 内部类所做的功能使用外部类也同样可以实现,只是有时候内部类做的更巧妙些. 内部类按照其所在位置不同,可分为以下