ZOJ 3857 Hypersphere 构造 + 矩阵快速幂
2015-07-17 13:56
393 查看
ZOJ 3857 Hypersphere
2013年长沙网络赛的一道题, 恩第一眼根本没看懂题意, 后来才知道这个题是给定K和L两个正整数之后求
⌊(L+L∗(L−1)−−−−−−−−−√)K⌋mod K 的值前面一部分是向下取整
这个题首先 直接通过快速幂来求的, 抛开浮点数误差不谈, K的值可能很大, 直接计算前面想下去整部分的话double应该都存不下
而这个题神奇的地方就在这里, 通过巧妙的共轭的构造使得原本计算的浮点数变成了整数
构造数列a 使得
a[t]=(L+L∗(L−1)−−−−−−−−−√)t+(L−L∗(L−1)−−−−−−−−−√)t
那么a[t]的左半部分是我们需要的, 而对于右半部分, 可以发现对于L >= 1, 这是一个最大为1, 最小是0.5的数的t次方, 证明如下:
(L−L∗(L−1)−−−−−−−−−√)=L−−√(L−−√−L−1−−−−−√)=L√L√+L−1√=11+1−1L√
当L = 1时最大时1, L趋近于无穷大是其值为0.5, 所以右半部分一定是一个最大为1的数, 并且可以趋近至0
另外一个巧妙的地方就是, 这个数列a的每一项都是整数, 这个是数列中的一个结论, 首先二次方程的两个根是
x1=L+L(L−1)−−−−−−−√,x2=L−L(L−1)−−−−−−−√
可以发现
x1+x2=2L,x1x2=L
这是方程x2−2Lx+L=0的两个根于是通过
a[0]=2,a[1]=2∗L, 且有方程a[i+1]−2La[i]+La[i−1]=0得到所有的数列a中的数(这个数列递推什么的是高中数学竞赛里的内容吧..)
因为数列a中的数都是整数, 可以在递推的同时进行取模操作, 另外由于最后只需要左边的项, 而右边那项的值不超过1, 只需要将最后得到的结果减去1就可以了, 相当于浮点数向下取整的操作
至于数列a的转移方程, 很明显是线性转移, 通过矩阵快速幂来加速计算即可, 例如构造矩阵转移:[anan−1][2L−L10]=[an+1an]
代码如下:
2013年长沙网络赛的一道题, 恩第一眼根本没看懂题意, 后来才知道这个题是给定K和L两个正整数之后求
⌊(L+L∗(L−1)−−−−−−−−−√)K⌋mod K 的值前面一部分是向下取整
这个题首先 直接通过快速幂来求的, 抛开浮点数误差不谈, K的值可能很大, 直接计算前面想下去整部分的话double应该都存不下
而这个题神奇的地方就在这里, 通过巧妙的共轭的构造使得原本计算的浮点数变成了整数
构造数列a 使得
a[t]=(L+L∗(L−1)−−−−−−−−−√)t+(L−L∗(L−1)−−−−−−−−−√)t
那么a[t]的左半部分是我们需要的, 而对于右半部分, 可以发现对于L >= 1, 这是一个最大为1, 最小是0.5的数的t次方, 证明如下:
(L−L∗(L−1)−−−−−−−−−√)=L−−√(L−−√−L−1−−−−−√)=L√L√+L−1√=11+1−1L√
当L = 1时最大时1, L趋近于无穷大是其值为0.5, 所以右半部分一定是一个最大为1的数, 并且可以趋近至0
另外一个巧妙的地方就是, 这个数列a的每一项都是整数, 这个是数列中的一个结论, 首先二次方程的两个根是
x1=L+L(L−1)−−−−−−−√,x2=L−L(L−1)−−−−−−−√
可以发现
x1+x2=2L,x1x2=L
这是方程x2−2Lx+L=0的两个根于是通过
a[0]=2,a[1]=2∗L, 且有方程a[i+1]−2La[i]+La[i−1]=0得到所有的数列a中的数(这个数列递推什么的是高中数学竞赛里的内容吧..)
因为数列a中的数都是整数, 可以在递推的同时进行取模操作, 另外由于最后只需要左边的项, 而右边那项的值不超过1, 只需要将最后得到的结果减去1就可以了, 相当于浮点数向下取整的操作
至于数列a的转移方程, 很明显是线性转移, 通过矩阵快速幂来加速计算即可, 例如构造矩阵转移:[anan−1][2L−L10]=[an+1an]
代码如下:
/* * Author: Gatevin * Created Time: 2015/7/17 13:27:13 * File Name: ZOJ3857.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; lint K, L; struct Matrix { lint a[4][4]; Matrix() { for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) a[i][j] = i == j ? 1 : 0; } lint* operator [] (int i) { return a[i]; } }; Matrix operator * (Matrix &m1, Matrix &m2) { Matrix ret; for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) { ret[i][j] = 0; for(int k = 0; k < 2; k++) ret[i][j] = (ret[i][j] + m1[i][k]*m2[k][j]) % K; } return ret; } Matrix quick(Matrix base, int pow) { Matrix I; while(pow) { if(pow & 1) I = I*base; base = base*base; pow >>= 1; } return I; } int main() { while(~scanf("%lld %lld", &K, &L)) { Matrix A; A[0][0] = 2*L % K; A[0][1] = 1; A[1][0] = (L % K == 0) ? 0 : K - (L % K); A[1][1] = 0; A = quick(A, K - 1); lint ans = (2*L*A[0][0]) % K + (2*A[1][0]) % K; ans = (ans - 1 + K) % K; printf("%lld\n", ans); } return 0; }
相关文章推荐
- 微软Word 2007数学插件 Microsoft Math 提供下载
- 关于C# Math 处理奇进偶不进的实现代码
- C#使用Matrix执行缩放的方法
- JavaScript中的Math.SQRT1_2属性使用简介
- JavaScript Math.ceil() 函数使用介绍
- 与Math.pow 相反的函数使用介绍
- JavaScript中使用指数方法Math.exp()的简介
- JavaScript使用Math.Min返回两个数中较小数的方法
- Ajax获取页面被缓存的解决方法
- JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
- 如何使用Matrix对bitmap的旋转与镜像水平垂直翻转
- JavaScript中Math对象使用说明
- javascript对象之内置对象Math使用方法
- 基于java math API 的详细解释说明
- 简介JavaScript中用于处理正切的Math.tan()方法
- 浅谈JavaScript中的Math.atan()方法的使用
- PHP内置的Math函数效率测试
- 在JavaScript中使用对数Math.log()方法的教程
- JavaScript中用于四舍五入的Math.round()方法讲解
- 简介JavaScript中Math.LOG10E属性的使用