题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4506
暴力果断超时,于是又从网上和Hdu的群里学了一个算法。
蒙哥马利幂模
思想:
在幂模运算中,通常是用幂模运算转换为乘模运算。有以下两个公式:
1)a*b%n=(a%n)*(b%n)%n
2)(a+b)%n=(a%n+b%n)%n
当我们计算D=C^15%N时,有:
C1=C*C%N=C^2%N
C2=C1*C%N=C^3%N
C3=C2*C2%N=C^6%N
C4=C3*C%N=C^7%N
C5=C4*C4%N=C^14%N
C6=C5*C%N=C^15%N
所以,幂模运算可以转化为乘模运算。继续看,我们会发现,要求D=C^E%N,要知道E何时能整除2,并不需要反复进行减一或者除二的操作,只需要验证E的二进制个位是0还是1就行了。
#include <cstdio>
__int64 data[10005],ans[10005];
__int64 Cal (__int64 s,__int64 index,__int64 mod)
//蒙哥马利幂模算法
//快速幂
//返回值(s^index)%mod
{
__int64 ans=1;
s%=mod;
while (index>=1)
{
if ((index&1)==1) //奇数
ans=(ans*s)%mod;
index>>=1;
s=s*s%mod;
}
return ans;
}
int main ()
{
#ifdef ONLINE_JUDGE
#else
freopen("read.txt","r",stdin);
#endif
int T;
scanf("%d",&T);
while (T--)
{
int t,n,k,i;
scanf("%d%d%d",&n,&t,&k);
__int64 temp=Cal(k,t,1000000007);
int dis=t%n; //经过t次,后移了多少位
for (i=0;i<n;i++)
{
scanf("%I64d",&data[i]);
ans[i]=data[i]*temp%1000000007;
}
for (i=n-dis;i<n;i++)
printf("%I64d ",ans[i]);
for (i=0;i<n-dis;i++)
printf(i!=n-dis-1?"%I64d ":"%I64d\n",ans[i]);
}
return 0;
}
1420
#include <cstdio>
int main ()
{
int T;
scanf("%d",&T);
while (T--)
{
__int64 a,b,c,k=1;
scanf("%I64d%I64d%I64d",&a,&b,&c);
a%=c;
while (b>=1)
{
if ((b&1)==1) //奇数
k=(k*a)%c;
b>>=1;
a=a*a%c;
}
printf("%d\n",k);
}
return 0;
}