快 速 幂
利用快速幂,可以极大提高运算速度,一般有数的快速幂,也有矩阵的快速幂,原理一样
a^b mod c=(a^2)^(b/2) mod c (b为偶数);
a^b mod c=((a^2)^(b div 2)*a) mod c (b为奇数)利用位操作,很快!
【常规版(非快速幂法)】
int pow1( int a, int b ) {
int r = a;
while( b-- )
r *= a;
return r;
}
int pow2( int a, int b ) {
int r = 1, base = a;
while( b != 0 ) {
if( b % 2 )
r *= base;
base *= base;
b /= 2;
}
return r;
}
int pow3( int a, int b ) {
int r = 1, base = a;
while( b != 0 ) {
if( b & 1 )
r *= base;
base *= base;
b >>= 1;
}
return r;
}
(我觉得吧,就快了一点点。。。)
int power4(int x, int n)
{
if (n == 0) {
return 1;
} else {
while ((n & 1) == 0) {
n >>= 1;
x *= x;
}
}
int result = x;
n >>= 1;
while (n != 0) {
x *= x;
if ((n & 1) != 0)
result *= x;
n >>= 1;
}
return result;
}
【矩阵快速幂(最是常用)】
#include
#include
#include
#include
#define sizer 3
using namespace std;
int N;
struct matrix {
int a[sizer][sizer];
} origin,res;
matrix multiply(matrix x,matrix y)
{/**定义矩阵乘法,不过,都是方阵*/
matrix temp;
memset(temp.a,0,sizeof(temp.a));
for(int i=0; i
>=1; origin=multiply(origin,origin); } } void print(matrix m, int sizee) { for(int i=0; i
#include
#include
#include
#include
#define sizer 3
using namespace std;
int N;
struct matrix {
int a[sizer][sizer];
} origin,res;
matrix multiply(matrix x,matrix y)
{/**定义矩阵乘法,不过,都是方阵*/
matrix temp;
memset(temp.a,0,sizeof(temp.a));
for(int i=0; i
>=1; origin=multiply(origin,origin); } } void print(matrix m, int sizee) { for(int i=0; i
boj428 田田的账号(规律+数值的快速幂)
题目描述
田田申请了一个新的oj账号,打算取一个霸气而简单的名字。 什么叫简单呢?说白了田田脑子不好使,只能记住abcd这4个字母组成单词。 怎么叫霸气呢?田田认为a个个数一定要有奇数个,b的个数一定要有偶数个(包括0)才可以。 现在田田取了一个长为n的账号,但是由于田田的记性实在太差了,而把账号忘记了. 于是把这个问题交给了聪明的wzt,而他认为这道题太过于简单就把这道题交给了你 究竟这个账号有多少种可能?你只需得到这个结果模
109+7
的值
输入样例
2(T,case数)
1(n取值)
2
输出样例
1
4
这道题目的规律我是老早就猜出来了,可是就是过不了啊过不了啊,这是为什么哩,一语点醒幂中人啊——“快速幂”
1.规律:打表也可以,不过动用一下逻辑思维可以直接推:
记a的个数为奇数,b的个数为偶数的账号排列数为A;
记a的个数为奇数,b的个数为偶数的账号排列数为B;很显然,有对称性,A=B,明显对不对;
你还会发现ab数对和cd数对也有对称性;
我们知道密码一共4的n次方个,两个对称性,除以2再除以2,结果就是4的n-1次方。
2.快速幂(快速幂取余):
当然啦,本题是要取余的,所以还是有所不同的。而且而且,必须要注意数的边界边界边界。。。
#include
#define ko 1000000007/**这种雷打不动的数,用常量定义最好啦*/
int quickpow_mod(int a,int n,int k)
{
int b=1; /**初始化这种东西,玩死人。。。*/
long long int b_,a_;/**越界这种东西,直接让你死*/
while(n>0){
if(n & 1){
b_=(long long)b;
b_=(b_*a)%k;
b=b_;
}
n=n>>1;
a_=a;
a_=(a_*a_)%k;
a=a_;
}
return b;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
printf("%d\n",quickpow_mod(4,n-1,ko));
}
}
hdu4686 Arc of Dream(矩阵快速幂)
题目描述
起始值 a0 = A0 ; b0 = B0 ; 递推式 ai = ai-1* AX + AY ; bi = bi-1* BX + BY ;
最后求 AoD(n)的值 mod 1,000,000,007
解题思路
首先,你得构造矩阵,这是个很麻烦的事,不过呢,如果你能写出递推式,那就没什么了,
来看这个式子:ai*bi=(ai-1 *ax+ay)*(bi-1 *bx+by)
=(ai-1 * bi-1 *ax*bx)+(ai-1 *ax*by)+(bi-1 *bx*ay)+(ay*by)
看见了,和ai,bi相关联的事 ai-1*bi-1, ai-1, bi-1, 然后就全是常数了,于是我们想:
令 p=ax*bx, q=ax*by, r=ay*bx, s=ay*by s(n)=sum(ai*bi),i=0,1,...n
则 ai*bi=p(ai-1 * bi-1)+q(ai-1)+r(bi-1)+s s(i)=s(i-1)+ai*bi
对于任何一个递推式,我们都可以用矩阵法来优化,加快速度求出第n项或前n项和 =>
特别棒,以就该多学学怎么构造
输入输出
Sample Input
1(N,表示n,就是幂次)
1 2 3(分别对应 A0, AX, AY )
4 5 6(分别对应 B0, BX, BY )
2
1 2 3
4 5 6
3
1 2 3
4 5 6
(N <= 1018, and all the other integers <= 2×109.)
Sample Output
4
134
1902
解题总结
1. LL坑得好惨,一定要注意int 和 LL 的区别,为此我居然 TTTTT。。。
2. 当N为0时,要特判
3. 请保持随处取余的好习惯!!!
代码
#include
#include
#include
#include
#define sizer 5
#define modvalue 1000000007
using namespace std;
typedef long long ll;
ll a[sizer][sizer],res[sizer][sizer],temp[sizer][sizer];
void multiply(ll x[][5],ll y[][5])
{
for(int i=0; i
>=1; } } void print(ll m[][5], int sizee) { for(int i=0; i