• 8.29 我们自己的世界


    题意

    给一个大小为(N)的数组(A),每次对数组进行如下的变换:

    • (B[i]=A[i]oplus A[i+1])
    • (A[i]=B[i])

    这里的(oplus)运算指异或

    我们会发现每次数组(A)的长度会减一,当数组(A)的长度减至一时,结束变换

    如果我们把每次变换后的(A)数组的第一项保存下来,记为(A_0[1],A_1[1]...A_{n-1}[1])

    [oplus sum_{i=0}^{n-1}A_i[1] imes (i+1) ]

    这里的(oplus sum)指的是异或和运算

    (N leq 8 imes 10^6)


    解法

    这题解法巨巧妙

    画出一个类似菱形网格图的结构,观察一下每次变换后的第一项是被哪些元素异或几次组成的

    把元素编号由(1,2..n)改为(0,1...n-1)

    我们能观察到如下的规律

    变换(/)元素 (a_0) $a_1 $ $a_2 $ (...) (a_{n-1})
    (1) (1) (0) (0) (0) (0)
    (2) (1) (2) (1) (0) (0)
    $... $
    (n) (C_n^0) (C_n^1) (C_n^2) (...) (C_n^{n-1})

    这不就是个杨辉三角吗?

    我们知道,异或次数为奇数的有贡献,异或次数为偶数的无贡献

    那么现在我们需要快速求出组合数的奇偶性

    根据卢卡斯定理,我们知道

    [C_n^m pmod p = C_{n\%p}^{m\%p} imes C_{n/p}^{m/p} ]

    现在我们需要判断其奇偶性,就需要模一个(2)

    [C_n^m pmod 2 = C_{n\%2}^{m\%2} imes C_{n/2}^{m/2} ]

    我们可以把(\%2)(/2)视作二进制位下的操作,即

    [C_n^mpmod 2=C_{n&1}^{m&1} imes C_{n>>1}^{m>>1} ]

    研究一下(C_{n&1}^{m&1})我们发现,只有(n)为偶数(m)为奇数时这个数为(0),其余均为(1)

    也就是(n)的某一位为(0)(m)的某一位为(1)时,这个数为(0)

    所以我们可以发现

    [C_n^m pmod 2 = 1 (m & n=m)\ C_n^m pmod 2 = 0 (otherwise) ]

    所以当(m)(n)的子集时,元素(a_m)会对第(n)次变换的第一个元素有贡献

    [b_n=oplus sum_{d& n=n}a_d ]

    最后的答案即为

    [ans=oplus sum_{i=0}^{n-1} (i+1) imes b_i ]

    于是现在的问题转化为了求(b)数组,也就是对于数组(a)每个位置上求一遍子集和

    这个可以用(FWT),但更方便的是采用(FMT),代码比较短

    本质上就是做一个(n)维的前缀和,一维一维的累加答案

    代码

    #include <cstdio>
    
    using namespace std;
    
    const int N = 8e6 + 10;
    
    int n;
    
    long long a, b, c, d;
    long long A[N];
    
    int main() {
    	
    	scanf("%d%lld%lld%lld%lld", &n, &a, &b, &c, &d);
    	
    	A[0] = a;
    	for (int i = 1; i < n; ++i)
    		A[i] = (A[i - 1] * A[i - 1] % d + b * A[i - 1] % d + c)	% d;
    	
    	for (int i = 0; i < 23; ++i) 
    		for (int j = 0; j < n; ++j) 
    			if ((j >> i) & 1)	A[j] ^= A[j ^ (1 << i)];
    		
    	long long ans = 0;
    	for (int i = 0; i < n; ++i)	ans ^= A[i] * (i + 1);
    	
    	printf("%lld
    ", ans);	
    		
    	return 0;		
    }
    
  • 相关阅读:
    JAVA学习之常用集合List,Set,Map
    【收藏】SQL多行变一列
    sql 多个字段分组,删除重复记录,保留ID最小的一条
    【转】 JavaScript:history.go() 的妙用(转) 处理post回发后返回
    【转】SQL SERVER 2005中如何获取日期(一个月的最后一日、上个月第一天、最后一天、一年的第一日等等)
    require.context实现自动化导入文件
    Vue进阶——解析V-MODEL
    ES6 的遍历器接口 Iterator
    必须掌握的ES6新特性
    Vue自定义指令获取DOM元素
  • 原文地址:https://www.cnblogs.com/VeniVidiVici/p/11446692.html
Copyright © 2020-2023  润新知