B -- 数论你还会快速幂
Time Limit:5s Memory Limit:256MByte
Submissions:405Solved:85
DESCRIPTION
今天HHHH在学数论,他看到一个很优美的式子:
∑ni=1ik mod p∑i=1nik mod p
一向热衷于抱队友大腿的HHHH便问队友ZZZZ怎么做
ZZZZ:"n,kn,k多大?"
HHHH:"105,105105,105"
ZZZZ:"快速幂嘛"
HHHH:"109,105109,105"
ZZZZ:"拉格朗日插值嘛"
HHHH:"1018,10181018,1018"
队友:"让我想想.."
INPUT
第一行是一个整数
T(1≤T≤1000)T(1≤T≤1000),表示有
TT组数据对于每组数据输入一行3个整数
n,k,p(1≤n≤1018,0≤k≤1018,1≤p≤1018,0≤n−p≤100)n,k,p(1≤n≤1018,0≤k≤1018,1≤p≤1018,0≤n−p≤100)且模数
pp 是质数,
OUTPUT
对于每组数据输出题目中的表达式的值
SAMPLE INPUT
2
5 2 3
7 2 3
SAMPLE OUTPUT
1
2
HINT
对于第一组样例我们有
12+22+32+42+52=1(mod3)12+22+32+42+52=1(mod3)对于第二组样例我们有
12+22+32+42+52+62+72=2(mod3)12+22+32+42+52+62+72=2(mod3)
SOLUTION
通过打表能够找到规律:
①首先我们知道,i^k%p和(i+p)^k%p的价值是一样的。
那么肯定以长度p为循环节,是有循环内容的。
②当k不是p-1的倍数的时候,我们发现,每一段长度为p的内容加和%p都是0.
②当k是p-1的倍数的时候,我们发现,每一段长度为p的内容加和都是p-1.
那么按照这个规律写一下即可。
注意k==0的时候。
Ac代码:
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long int
ll n,p,k;
ll kuaisucheng(ll a,ll b)
{
ll ans=0;
while(b)
{
if(b&1)
{
ans=(ans+a);
if(ans>=p)ans-=p;
}
a=(a+a);
if(a>=p)a-=p;
b/=2;
}
return ans;
}
ll kuaisumi(ll a,ll b)
{
a%=p;
ll ans=1;
while(b)
{
if(b&1)
{
ans=kuaisucheng(ans,a);
}
a=kuaisucheng(a,a);
b/=2;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&k,&p);
if(k==0)
{
printf("%lld\n",n%p);
continue;
}
ll sum=0;
if(k%(p-1)==0)
{
sum+=kuaisucheng((ll)n/p,p-1);
sum%=p;
}
n%=p;
for(ll i=1;i<=n;i++)
{
sum+=kuaisumi(i,k);
sum%=p;
}
printf("%lld\n",sum%p);
}
}