沉默是金 矩阵快速幂

沉默是金

时间限制: 1 Sec  内存限制: 128 MB

题目描述

终于活成了自己最讨厌的模样。

小希遇到了一个序列,他现在可以在序列中可以有重复地取k个数组成一个新的序列。该序列有以下几个性质:

1、长度为k;

2、序列中的数字满足相邻两个数字异或后的二进制数字中1的个数是3的倍数。

一共有多少个满足条件的序列?

输入

有多组测试样例。

第一行两个数n,k代表给定序列的长度和待取序列的长度。

接下来一行n个数字,代表给定序列。

输出

每个答案一行,输出满足条件的序列的个数。答案模1000000007

样例输入

5 2
15 1 2 4 8
10 1
44 65 23 44 100 19 19 23 19 40
10 2
93 93 85 48 44 98 93 100 98 98
10 100
22 0 41 63 22 41 17 22 15 42
10 1000000000
454240622 216977025 454240622 509843007 509843007 26552516 488949284 708817573 453191950 447767457

样例输出

13
10
52
205668186
108319885

题意:

给定序列,从序列中选择k(1≤k≤1e18)个数(可以重复选择),使得得到的排列满足xi与xi+1异或的二进制表示中1的个数是3的倍数。问长度为k的满足条件的 序列有多少种?

分析:

首先每个元素自己构成一个长度为1的满足条件的序列。 
其次我们可以预处理出满足条件的vi,vj,就可以得到一个横纵为n的01矩阵。此时我们得到了以vi开头,vj结尾的长度为2的序列个数。 
接下来我们发现,两个矩阵相乘,矩阵c为新得到的矩阵,此时矩阵a=b,c[i][j]=a[i][1]∗b[1][j]+a[i][2]∗b[2][j]+...+a[i][n]∗b[n][j],我们得到的即为以ai开头,aj结尾的长度为3的序列个数! 
接下来用矩阵c更新矩阵a,再与最初的01矩阵,即b相乘,得到的又为开头元素为ai,结尾元素为aj的长度为4的序列个数! 
依次乘k−1次即得到结果,这部分可以用矩阵快速幂进行优化。 
 

#include<bits/stdc++.h>
using namespace std;
const int maxn=101;
const int mod=1000000007;
struct node
{
    int l;//行
    int r;//列
    long long a[maxn][maxn];
};

node init(node a)//初始化矩阵
{
    for(int i=1;i<=a.r;i++)
        for(int j=1;j<=a.l;j++)
            a.a[i][j]=0;
    return a;
}

node mul(node a,node b)//矩阵乘法
{
    node c;
    c.l=a.l;c.r=b.r;
    for(int i=1;i<=c.l;i++)
        for(int j=1;j<=c.r;j++)
        {
            c.a[i][j]=0;
            for(int k=1;k<=a.r;k++)
            {
                c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
            }
        }
    return c;
}

node quickm(node a,int m)//矩阵快速幂
{
    int i=0;
    node b;
    b.l=b.r=a.l;
    b=init(b);
    for(int i = 1;i<=b.l;i++){
        b.a[i][i] = 1;
    }
    while(m){
        if(m&1)
        b=mul(b,a);
        a=mul(a,a);
        m>>=1;
    }
    return b;
}

int count(long long  a)//统计a的二进制中1的个数
{
    int ans = 0;
    while(a){
        if(a & 1) ans++;
        a >>= 1;
    }
    return ans;
}

int main()
{
    long long n,k,z[maxn];
    while(cin>>n>>k)
    {
        for(int i=1;i<=n;i++)
        {
            cin>>z[i];
        }
        node A;
        A.r=A.l=n;
        A=init(A);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(count(z[i]^z[j])%3==0)
                {
                    A.a[i][j]=1;
                }
            }
        long long ans=0;
        A=quickm(A,k-1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                ans+=A.a[i][j];
                ans%=mod;
            }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/81737928