Codeforces 691E Xor-sequences【矩阵快速幂,好题】
2016-07-15 21:01
573 查看
题目链接:
http://codeforces.com/problemset/problem/691/题意:
给定序列,从序列中选择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次即得到结果,这部分可以用矩阵快速幂进行优化。
最后把得到的矩阵中的每个元素的值加起来即为长度为k的满足条件的序列个数!
实质上就是floyd求长度为k的道路。
巧妙的利用矩阵乘法的性质解决问题!这很矩阵!
代码:
/************************************************************************* > File Name: R.cpp > Author: jiangyuzhu > Mail: 834138558@qq.com > Created Time: 2016/7/15 18:51:12 ************************************************************************/ #include<cstdio> #include<iostream> #include<cstdlib> #include<queue> #include<cstring> #include<stack> #include<vector> #include<algorithm> #include<map> #include<cmath> using namespace std; #define pr(x) cout << #x << ": " << x << " " #define pl(x) cout << #x << ": " << x << endl; #define sa(x) scanf("%d",&(x)) #define sal(x) scanf("%I64d",&(x)) typedef long long ll; const int maxn = 105, mod = 1e9 + 7; ll a[maxn]; int n; const int N = 105; struct Matrix { int row,cal; long long m ; }; Matrix init(Matrix a, long long t) { for(int i = 0; i < a.row; i++) for(int j = 0; j < a.cal; j++) a.m[i][j] = t; return a; } Matrix mul(Matrix a,Matrix b) { Matrix ans; ans.row = a.row, ans.cal = b.cal; ans = init(ans,0); for(int i = 0; i < a.row; i++) for(int j = 0; j < b.cal; j++) for(int k = 0; k < a.cal; k++) ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j])%mod; return ans; } Matrix quick_pow(long long k, Matrix A) { Matrix I; I.row = n, I.cal = n; I = init(I, 0); for(int i = 0; i < n; i++){ I.m[i][i] = 1; } while(k){ if(k & 1) I = mul(I, A); A = mul(A, A); k >>= 1; } return I; } int count(ll a) { int ans = 0; while(a){ if(a & 1) ans++; a >>= 1; } return ans; } int main(void) { sa(n); ll k;sal(k); for(int i = 0; i < n; i++){ sal(a[i]); } Matrix A; A.row = n, A.cal = n; A = init(A, 0); for(int i = 0 ; i < n; i++){ for(int j = 0; j < n; j++){ if(count(a[i] ^ a[j]) % 3 == 0){ A.m[i][j] = 1; } } } ll ans = 0; A = quick_pow(k - 1, A); for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ (ans += A.m[i][j]) %= mod; } } printf("%I64d\n", ans); return 0; }
相关文章推荐
- 《Testing with Xcode》第一章——QuickStart
- 最大堆---实现一个简化的搜索提示系统。给定一个包含了用户query的日志文件,对于输入的任意一个字符串s,输出以s为前缀的在日志中出现频率最高的前10条query。
- UVA-424 Integer Inquiry
- UVA 133 The Dole Queue
- userInteractionEnabled交互性
- 使用 Bluemix 和 DevOps Services 的十大理由
- UVa 1594(Ducci Sequence)
- 【leetcode】374. Guess Number Higher or Lower【E】
- 解决Exception raised during rendering: Could not find layout resource matching value...问题
- [个人博客搬运]定制UICollectionViewLayout实现集合视图
- [Leetcode]303. Range Sum Query - Immutable
- rabbitMQ guest账号登录总是提示失败
- AbstractSequentialList抽象类源码解析
- UESTC 2016 Summer Training #5 Div.2(未完待续)
- NGUI 背包滑动整合
- HoloLens开发手记 - Known issues 已知问题
- java 解析json 遍历未知key与value
- String 的个人理解以及在栈堆的内存以及Stringbuilder和Stringbuffer
- 约束报错、冲突如何定位UI
- 快速(quick)排序算法