描述
2014年1月ACM爱好者协会寒假集训期间,大家一定不会忘记的是17号下午在西配317开的生日party吧。
17号是某知名大牛lzwjava的生日,18号是某知名大牛cnsks的生日,于是fudq决定在17日下午开个生日party,庆祝两位大牛生日快乐。lzwjava和cnks给大家买了大蛋糕和好多好多吃的,桌上满满的全是吃的喝的,大家一起玩了好多游戏,场面相当嗨皮。A协其乐融融,所有人都好好玩了一下午。
最后大家一起点上蜡烛,唱生日歌,寿星许完愿之后当然是切蛋糕了,两位寿星亲自操刀,把蛋糕切好分给大家吃。fudq发现寿星切蛋糕有个规律,后面切的蛋糕比前面的大,而且从头到尾排列起来发现是个等比数列,但是光顾着嗨皮的fudq只记住了前两块蛋糕的大小,现在他想知道第K块蛋糕有多大?假设蛋糕有足够大。
输入
输入第一行是一个正整数T(1<=T<=30),表示接下来有T组测试数据。
接下来有T行,每行代表一组数据,每组数据包含有三个正整数a,b,K,其中a,b表示前两块蛋糕的大小,并且一定构成等比数列.1<=a<=b<=1,000,000,000,1<=K<=1,000,000,000,b%a=0.
输出
每组数据输出占一行,输出第K块蛋糕的大小,当然结果会很大,fudq只要求求出对20140119取余的结果。
样例输入
3
1 1 10
2 4 5
3 3000000 1000000000
样例输出
1
32
17398380
代码:
#include
#define n 20140119
__int64 powhh(__int64 x,__int64 k,__int64 w)
{
while(k>0)
{
if(k&1)
{
x*=w;
x%=n;
k--;
}
k/=2;
w*=w;
w%=n;
}
return x;
}
int main()
{
__int64 a,b,k,x,q,w,t;
//freopen("Data.txt","r",stdin);
while((scanf("%I64d",&t))!=EOF)
{
while(t--)
{
scanf("%I64d%I64d%I64d",&a,&b,&k);
q=b/a;
k--;
x=a%n;
w=q%n;
printf("%I64d\n",powhh(x,k,w));
}
}
return 0;
}
总结:当有一个初始值要乘以很多个相同的数时,可以用快速降幂的方法。这里借用王博学长打出的快速幂函数:(自己按理解改动一点吧)
这个函数是算这么个东西的:x*m^n;(当n很大的时候,算这个式子很容易超时。。(当然也容易超范围,所以一般都会取余))
__int64 powhaha(__int64 x,__int64 n,__int64 m) //m表示要乘的数,n表示要乘多少次。
{
while(n>0)
{
if(n&1) //<=>if(n&1>0)判断n是奇数还是偶数,如果是n是奇数,n&1=1,如果n是偶数,n&1=0;
{
x*=m;
n--; //为了好理解,这个是我自己加上去的。。。其实不加也可以,因为后面n/=2和(n--)/2;是等价的。
}
m*=m; //然后同时乘以两个m。。。
n/=2; //既然同时乘了两个m,那肯定就只要乘以n/2次了。。
}
return x;
}
原理:
(ans=1)*n*n*···*n(m个n)
<------<---------------<---------------
if(m为偶数),那么可以化为 |
(ans=1)*(n*n)*(n*n)*···*(n*n)(m/2个(n*n)) |
if(m为奇数,把一个n放入ans中) |
(ans=n)*n*n*···*n(m-1个n) | 循环,每次新的n等于原来的n*n,新的m=原来的m/2;
这是m-1为偶数,那么等式就可以简化为 |
(ans=n)*(n*n)*(n*n)*···*(n*n)((m-1)/2个(n*n)) |
| |
--------------------->-----------------|快速幂再加上个取余就变成了快速幂取余。。。这样既不会超时也不会超范围了。。。
快速幂取余差不多就是(x*m^n)%k,原理是:(a*b)%c==((a%c)*(b%c))%c;
函数可以这样写:
__int64 powhaha(__int64 x,__int64 n,__int64 m,__int64 k)
{
while(n>0)
{
if(n&1)
{
x*=m;
x%=k;
}
m*=m;
m%=k;
n/=2;
}
return x;
}
其实就是加了红色的两步。。。
好了,写完了