zoukankan      html  css  js  c++  java
  • World Of Our Own [Lucas+思维题]

    World Of Our OwnWorld Of Our Own

    ⼩C在研究数组的xor。
    她有⼀个长度为 nn 的数组 AA
    她每次会把ai1a_{i-1}aia_i异或起来,然后AA的长度会变成n1n - 1
    这么操作了n1n - 1次之后得到了长度为11的数组。
    她想知道在操作过程中每次的a1a_1为多少?
    为了避免输出过⼤,请输出第jj次操作后的a1×(j+1)a_1 imes (j + 1)的异或和(0jn10 leq j leq n - 1)。

    n8106,a,b,c,d109,a<dn le 8 * 10^6, a, b, c, d le 10^9, a < d


    color{red}{正解部分}

    将过程图画出如下
    (请自行脑补将所有下标减11)

    图中最左边一列的点从上向下分别表示第 0,1,2,30, 1, 2, 3 此操作后的 a1a_1,
    其左下角的数字表示其受数组中对应位置的异或和贡献,

    发现贡献系数是符合杨辉三角的规律的, 用语言表达出来就是: ijCij第 i 次操作后受位置 j 影响的贡献系数是 C_{i}^j,
    由于是异或操作, 当 贡献系数 是奇数的时候才会真正产生贡献 .

    那么什么时候 贡献系数 为奇数呢 ??, 换句话说, 什么时候 CijC_i^j 为奇数呢 ??
    考虑在模22的意义下使用 LucasLucas 定理 : CijCi%2j%2Ci/2j/2mod  2C_i^j ≡ C_{i\%2}^{j\%2}*C_{i/2}^{j/2} mod 2,

    先考虑第一项 Ci%2j%2C_{i\%2}^{j\%2}, 当且仅当 i%2=0,j%2=1i\%2=0, j\%2=1 的时候 Ci%2j%2C_{i\%2}^{j\%2}00,
    此时 ii 的二进制尾部为 00, jj 的二进制尾部为 11 , 由于是乘法, 这个 00 会导致整个式子归零 .

    再考虑第二项, 对 Ci/2j/2C_{i/2}^{j/2} 使用 LucasLucas 定理,
    在二进制表示下相当于 iijj 同时去掉尾部的一个二进制位之后的一个递归过程, 回到 考虑第一项 的情况 .

    于是综上所述可得: i&j=j,Cij=1,jia1.当 i & j = j 时, C_{i}^{j}=1, j 位置的数对第 i 次操作的 a_1 有贡献 .


    color{red}{实现部分}

    可以枚举 jj, 然后在 jj 的二进制上 “填” 11 得到一个可以贡献的 ii, 累计aja_j的贡献 .

    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 8500006;
    
    int N;
    int a;
    int b;
    int c;
    int d;
    int Rd[maxn];
    int sum[maxn];
    
    ll Ans;
    ll A[maxn];
    
    void Vio(){
            int cnt = 0;
            for(reg int i = N; i > 1; i --){
                    Ans ^= A[1]*(++ cnt);
                    for(reg int j = 1; j < i; j ++) A[j] = A[j]^A[j+1];
            }
            Ans ^= A[1]*(++ cnt);
            printf("%lld
    ", Ans);
    }
    
    void Work(){
            for(reg int j = 0; j <= 22; j ++)
                    for(reg int i = 0; i < N; i ++)
                            if(!(i & (1<<j))) A[i|(1<<j)] ^= A[i];
            for(reg int i = 0; i < N; i ++) Ans ^= A[i]*(i+1);
            printf("%lld
    ", Ans);
    }
    
    int main(){
            scanf("%d%d%d%d%d", &N, &a, &b, &c, &d);
            A[0] = a;
            for(reg int i = 1; i < N; i ++) A[i] = (A[i-1]*A[i-1] + 1ll*b*A[i-1] + c) % d;
            Work();
            return 0;
    }
    
  • 相关阅读:
    js 基于可视区域 创建展示区域对应的经纬度二维数组
    主要看思路:区域数据去重 + JavaScript一次性展示几万条数据实例代码
    推荐js库: underscore
    开博缘由 , 可点下看看 http://www.cnblogs.com/jshare
    php--sphinx的使用
    php--validate表单验证实例
    php--validate错误信息提示样式
    php--yii框架中的ajax分页与yii框架自带的分页
    php--jquery操作全选、批量删除、加减行
    php--yii2.0框架的curl
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822506.html
Copyright © 2011-2022 走看看