BNUOJ28891 Choosing number(矩阵快速幂)
2015-07-22 11:43
357 查看
题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=28891
题意:
有n个人 选择m个数; 每个人可以任意选数 , 若2个相邻的人选择相同的数,当且仅当这个数大于k; 问总共有多少种方法选择数
分析:
对于这道题, 比赛的时候完全没想法, 怎么也没想到是矩阵快速幂;看了别人的博库之后, 仔细想想之后,好像只能用快速幂来做题, 问什么呢? 因为这道题数据很大,普通的方法遍历一次就已经超时了。 搜索更不可能;dp也是遍历的,也是不行。 对于数据很大的我们可以用快速幂来做,以节省时间。 但是普通的快速幂根本没法用。 所以我们看这道题之后, 只找规律了。
对于第一个人, 我们设 x0为选的数不超过k的方法的有几种,设x1为选的数超过k的方法的有几种;
那么对于第二个人来说; y0 = x0*(k-1)+x2*k; y1= x0*(m-k)+x1*(m-k);
在我们找到这个规律之后, 我们就可以很清楚明白用矩阵快速幂了。
下面就是要够造的矩阵
(y0, y1)= (x0, x1) (k-1, m-k)
(k, m-k)
做了这道题, 我又复习了一遍矩阵快速幂; 同时我发现在矩阵乘法中矩阵的顺序对结果是有影响的,就是矩阵乘法中相乘矩阵的位置不能颠倒(自己可以想想为什么)。
题意:
有n个人 选择m个数; 每个人可以任意选数 , 若2个相邻的人选择相同的数,当且仅当这个数大于k; 问总共有多少种方法选择数
分析:
对于这道题, 比赛的时候完全没想法, 怎么也没想到是矩阵快速幂;看了别人的博库之后, 仔细想想之后,好像只能用快速幂来做题, 问什么呢? 因为这道题数据很大,普通的方法遍历一次就已经超时了。 搜索更不可能;dp也是遍历的,也是不行。 对于数据很大的我们可以用快速幂来做,以节省时间。 但是普通的快速幂根本没法用。 所以我们看这道题之后, 只找规律了。
对于第一个人, 我们设 x0为选的数不超过k的方法的有几种,设x1为选的数超过k的方法的有几种;
那么对于第二个人来说; y0 = x0*(k-1)+x2*k; y1= x0*(m-k)+x1*(m-k);
在我们找到这个规律之后, 我们就可以很清楚明白用矩阵快速幂了。
下面就是要够造的矩阵
(y0, y1)= (x0, x1) (k-1, m-k)
(k, m-k)
做了这道题, 我又复习了一遍矩阵快速幂; 同时我发现在矩阵乘法中矩阵的顺序对结果是有影响的,就是矩阵乘法中相乘矩阵的位置不能颠倒(自己可以想想为什么)。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int mod = 1000000007; const int N = 2; struct Node { int row, cal; long long s ; Node() { row = cal = N; s[0][0] = 1, s[0][1] = 0; s[1][0] = 0, s[1][1] = 1; } }; Node Matble(Node a, Node b) { Node ans; ans.row = a.row; ans.cal = b.cal; for(int i = 0; i < ans.row; i++) for(int j = 0; j < ans.cal; j++) ans.s[i][j] = 0; for(int i = 0; i < ans.row; i++) { for(int j = 0; j < ans.cal; j++) { for(int k = 0; k < a.cal; k++) ans.s[i][j] = (ans.s[i][j] + a.s[i][k]*b.s[k][j]%mod)%mod; } } return ans; } long long pow_Matble(int n, int m, int k) { Node ans, temp, res; temp.s[0][0] = k-1, temp.s[0][1] = m-k; temp.s[1][0] = k, temp.s[1][1] = m-k; while(n) { if(n&1) ans = Matble(ans, temp); temp = Matble(temp, temp); n >>= 1; } temp.s[0][0] = k, temp.s[0][1] = m-k; temp.s[1][0] = 0, temp.s[1][1] = 0; res = Matble(temp, ans); long long sum = 0; for(int i = 0; i < res.cal; i++) sum =(sum + res.s[0][i])%mod; return sum; } int main() { int n, m, k; while(scanf("%d%d%d", &n, &m, &k) != EOF) { long long ans = pow_Matble(n-1, m, k); printf("%lld\n", ans); } return 0; }
相关文章推荐
- POJ-1011-Sticks-DFS(深搜)+四次剪枝
- Telnet协议详解 (转)
- C++ Primer 复习杂记(第三章)
- 安装和使用flume1.5传输数据(日志)到hadoop2.2
- debian 该分区的部分安装移动硬盘后无法识别。
- Java连接JDBC数据库
- 数据库端口号
- 7-11创始人:如何运用心理学让销量翻番?
- 14. JavaScript Date(日期)对象
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- 面向对象(二)(static,.final,抽象类,接口,内部类)
- 关于移位操作的一点说明
- Android开发之ListView+EditText-要命的焦点问题终极解决方案
- GRE写作必备句型
- 代码同步环境部署
- 4.1 成员函数的各种调用方式(静态成员函数,非静态成员函数,虚拟成员函数)
- Android Studio最新配置教程2016
- Oracle 中 decode 函数用法
- UIWebView 与 js/html 之间交互
- C#反射机制 (转载)