• Xor-sequences CodeForces


    Xor-sequences CodeForces - 691E

    题意:在有n个数的数列中选k个数(可以重复选,可以不按顺序)形成一个数列,使得任意相邻两个数异或的结果转换成二进制后其中1的个数是三的倍数。求可能形成的不同数列个数(只要选出的数列中,任意两个元素在原序列中的位置不同,就算作不同的序列,比如在原数列[1,1]中选1个,那么第一个1和第二个1要分开算)。

    方法:

    很容易列出dp方程:

    dp[k][i]表示取了k个,最后一个在第i位。a[i][j]表示i和j异或结果转换成二进制后1的个数是否是3的倍数,1表示是,0表示否。

    $dp[k][i]=dp[k-1][1]*a[1][i]+...dp[k-1][n]*a[n][i]$

    注意,不是$dp[k][i]=dp[k-1][1]*a[1][i]+...+dp[k-1][i-1]*a[i-1][i]$(这道题是可以重复、不按顺序选的,这么写就是不重复、按顺序)

    那么,这样的算法复杂度就是O(nk),太慢了,需要优化。

    从小数据开始:

    n=3时:
    
    dp[1][1]=1
    dp[1][2]=1
    dp[1][3]=1
    
    dp[2][1]=dp[1][1]*a[1][1]+dp[1][2]*a[2][1]+dp[1][3]*a[3][1]
    dp[2][2]=dp[1][1]*a[1][2]+dp[1][2]*a[2][2]+dp[1][3]*a[3][2]
    dp[2][3]=dp[1][1]*a[1][3]+dp[1][2]*a[2][3]+dp[1][3]*a[3][3]
    
    dp[3][1]=dp[2][1]*a[1][1]+dp[2][2]*a[2][1]+dp[2][3]*a[3][1]
    dp[3][2]=dp[2][1]*a[1][2]+dp[2][2]*a[2][2]+dp[2][3]*a[3][2]
    dp[3][3]=dp[2][1]*a[1][3]+dp[2][2]*a[2][3]+dp[2][3]*a[3][3]
    
    很容易可以发现:
    矩阵1
    dp[1][1] dp[1][2] dp[1][3]
    矩阵2
     a[1][1]  a[1][2]  a[1][3]
     a[2][1]  a[2][2]  a[2][3]
     a[3][1]  a[3][2]  a[3][3]
    矩阵1*矩阵2
    dp[2][1] dp[2][2] dp[2][3]
    

    更大的数据以此类推,因此很容易想到用矩阵快速幂优化。

    而要求dp[k][],就要由dp[1][]乘k-1次矩阵2,可以改为算出来矩阵2的k-1次幂放入矩阵3,再将dp[1][]乘上矩阵3,得到的就是dp[k][]。最终答案就是dp[k][1]+..+dp[k][n]。

    所以说...这个矩阵快速幂的题..居然不用自己去构造转移矩阵??

    另外:

    __builtin_popcountll:参照__builtin_popcount,那个是针对long整型的,这个是针对long long的

    还有手动写的

     1 #include<cstdio>
     2 #include<cstring>
     3 #define md 1000000007
     4 typedef long long LL;
     5 LL n,k,anss;
     6 LL a[101];
     7 struct Mat
     8 {
     9     LL data[101][101],x,y;
    10     Mat()
    11     {
    12         memset(data,0,sizeof(data));
    13         x=y=0;
    14     }
    15     Mat operator*(const Mat& b)
    16     {
    17         Mat temp;
    18         LL i,j,k;
    19         for(i=1;i<=x;i++)
    20             for(j=1;j<=b.y;j++)
    21                 for(k=1;k<=y;k++)
    22                     temp.data[i][j]=(data[i][k]*b.data[k][j]+temp.data[i][j])%md;
    23         temp.x=x;
    24         temp.y=b.y;
    25         return temp;
    26     }
    27     Mat& operator*=(const Mat& b)
    28     {
    29         return (*this)=(*this)*b;
    30     }
    31     Mat& operator=(const Mat& b)
    32     {
    33         memcpy(data,b.data,sizeof(data));
    34         x=b.x;
    35         y=b.y;
    36         return *this;
    37     }
    38 }ma,o,bbb,ccc;
    39 Mat pow(const Mat& a,LL b)
    40 {
    41     Mat ans=o;
    42     if(b==0)    return ans;
    43     Mat base=a;
    44     while(b!=0)
    45     {
    46         if(b&1!=0)    ans*=base;
    47         base*=base;
    48         b>>=1;
    49     }
    50     return ans;
    51 }
    52 int main()
    53 {
    54     LL i,j;
    55     scanf("%I64d%I64d",&n,&k);
    56     for(i=1;i<=n;i++)
    57         scanf("%I64d",&a[i]);
    58     ma.x=ma.y=n;
    59     for(i=1;i<=n;i++)
    60         for(j=1;j<=n;j++)
    61             ma.data[i][j]=(__builtin_popcountll(a[i]^a[j])%3==0);
    62     o.x=o.y=n;
    63     for(i=1;i<=n;i++)
    64         for(j=1;j<=n;j++)
    65             o.data[i][j]=(i==j);
    66     bbb=pow(ma,k-1);
    67     ccc.x=1;ccc.y=n;
    68     for(i=1;i<=n;i++)
    69         ccc.data[1][i]=1;
    70     ccc*=bbb;
    71     for(i=1;i<=n;i++)
    72         anss=(anss+ccc.data[1][i])%md;
    73     printf("%I64d",anss);
    74     return 0;
    75 }
  • 相关阅读:
    poj 2054 Color a Tree(贪婪)
    Restful 和 Jersey介绍(Web Service )
    Android异步载入全解析之使用多线程
    50个Android开发技巧(11 为文字加入特效)
    HDU 4424 Conquer a New Region 最大生成树
    Spring通过工厂创建实例的注意事项
    配置rhel 6.4(64位)安装使用syslog-ng 3.5
    虚拟机上网设置
    Java学习——何为JNDI
    Swift初体验 (一)
  • 原文地址:https://www.cnblogs.com/hehe54321/p/cf-691e.html
Copyright © 2020-2023  润新知