Xor-sequences CodeForces - 691E || 矩阵快速幂

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 }
时间: 2024-08-18 18:54:26

Xor-sequences CodeForces - 691E || 矩阵快速幂的相关文章

codeforces 185a(矩阵快速幂)

题意:三角形变化过程如下图 问正着的三角形的个数,n=1时1个,n=2时3个,n=3时10 - . 题解:可以找到规律 正x 倒y 1 0 3 1 10 6 - - 3*x+y 3*y+x 然后构造矩阵用矩阵快速幂求解. #include <cstdio> #include <iostream> #include <cstring> using namespace std; const int MOD = 1000000007; const int N = 3; str

codeforces 1182F 矩阵快速幂

题意:设f(n) = c ^ (2n - 6) * f(n - 1) * f(n - 2) * f(n - 3), 问第n项是多少? 思路:官方题解:我们先转化一下,令g(x) =  c ^ x * f(x), 那么原式转化为了g(x) = g(x - 1) * g(x - 2) * g(x - 3).之后我们可以考虑把f(1), f(2), f(3)和c的质因子找出来,枚举质因子对答案的贡献.我们发现,如果是质因子的数目的话,乘法就变成了加法(相当于统计质因子的指数),这样就可以用矩阵乘法优化

【矩阵快速幂 】Codeforces 450B - Jzzhu and Sequences (公式转化)

[题目链接]click here~~ [题目大意] Jzzhu has invented a kind of sequences, they meet the following property: You are given x and y, please calculate fn modulo1000000007(109?+?7). [解题思路] /*A - Jzzhu and Sequences Codeforces 450B - Jzzhu and Sequences ( 矩阵快速幂 )

Codeforces Round #257 (Div. 2) B. Jzzhu and Sequences (矩阵快速幂)

题目链接:http://codeforces.com/problemset/problem/450/B 题意很好懂,矩阵快速幂模版题. 1 /* 2 | 1, -1 | | fn | 3 | 1, 0 | | fn-1 | 4 */ 5 #include <iostream> 6 #include <cstdio> 7 #include <cstring> 8 using namespace std; 9 typedef __int64 LL; 10 LL mod =

Codeforces 450B div.2 Jzzhu and Sequences 矩阵快速幂or规律

Jzzhu has invented a kind of sequences, they meet the following property: You are given x and y, please calculate fn modulo 1000000007 (109 + 7). Input The first line contains two integers x and y (|x|, |y| ≤ 109). The second line contains a single i

Codeforces 450B - Jzzhu and Sequences ( 矩阵快速幂 )

题意: 给定f1和f2,求fn 分析: 特判f1,f2 当n>=3时使用矩阵快速幂即可( 简单题 ) 将公式转化一下 , 可以得到一个变换矩阵 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR( a, b ) memset( a, b, sizeof(a) ) #define MAT_SIZE 2 #define MOD 10

Codeforces Round #257 (Div. 2)B 矩阵快速幂

B. Jzzhu and Sequences time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Jzzhu has invented a kind of sequences, they meet the following property: You are given x and y, please calculate fn m

CodeForces 185A. Plant(矩阵快速幂)

题目链接:http://codeforces.com/problemset/problem/185/A Dwarfs have planted a very interesting plant, which is a triangle directed "upwards". This plant has an amusing feature. After one year a triangle plant directed "upwards" divides int

[递推+矩阵快速幂]Codeforces 1117D - Magic Gems

传送门:Educational Codeforces Round 60 – D 题意: 给定N,M(n <1e18,m <= 100) 一个magic gem可以分裂成M个普通的gem,现在需要N个gem,可以选择一定的magic gem,指定每一个分裂或不分裂,问一共有多少种方案 两种分裂方案不同当且仅当magic gem的数量不同,或者分裂的magic gem的索引不同. 思路: 1.首先从dp的角度出发 设F(i)为最终需要i个gem的方案数,容易得到递推式: (总方案数 = 最右边的m