题目描述
- 求:
-
i=1∑kpi2p−1modp2
- 其中p为质数
-
1≤k,p≤109
题目描述
其中最关键的是p是质数
方法一:
然后,“数论算个屁,打表找规律。” 就闪亮登场了!
首先我们枚举k与p,然后得出了以下的规律:
p=2,答案序列为:1,0,1,0,1,0,1,0,1,0,1,0…
p=3,答案序列为:6,6,0,6,6,0,6,6,0,6,6,0…
p=5,答案序列为:15,10,10,15,0,15,10,10,15,0…
p=7,答案序列为:28,14,7,7,14,28,0,28,14,7,7,14,28,0…
p=11,答案序列为:66,22,110,88,77,77,88,110,22,66,0…
由此,我们可以3个规律:
1.答案序列有循环节,且长度为p
2.每一个循环节都是回文的(0除外)
3.每一个数都可以被p整除
可即使这样,我们还是不能发现个所以然,所以我们还要简化。
这时,我们通过规律3,给每一个数除p
注:我们去掉p=2(因为太特殊),然后让循环节的回文串折半
p=3:2
p=5:3,2
p=7:4,2,1
p=11:6,2,10,8,7
只要对数字有点敏感的人,都可以看得出来,后一项与前一项的差,是一个等差数列!(当然,是在
modp意义下)
于是乎,我们便可以@#¥@¥#@%@#¥@#¥,AC!
方法二:
好吧,我们来一点正常点的方法。
首先,我们来证明一个式子:
∑i=1p−1i2p−1≡2p(p+1)(modp2)
我们来推一波
如果此式子是正确的,则:
∑i=1p−1[i2p−1+(p−i)2p−1]≡p(p+1)(mod2p)
∑i=1p−1[i2p−1+(2p−1)pi2p−2−i2p−1]≡p(p+1)(modp2)
∑i=1p−1(2p−1)pi2p−2≡p(p+1)(modp2)
∑i=1p−1(2p−1)i2p−2≡(p+1)(modp)
∑i=1p−1(2p−1)≡(p+1)(modp)
(p−1)(2p−1)≡1(modp)
1≡1(modp)
接着让我们来看一下原来的式子:
∑i=1kpi2p−1modp2
让我们继续去推一波
∑i=0k−1∑j=1p(ip+j)2p−1modp2
∑i=0k−1∑j=1p−1(ip+j)2p−1modp2
∑i=0k−1∑j=1p−1j2p−1+(2p−1)ipj2p−2modp2
2kp(p+1)+∑i=0k−1∑j=1p−1(2p−1)ipj2p−2modp2
2kp(p+1)+∑i=0k−1i∗∑j=1p−1(2p−1)pj2p−2modp2
到了这一步,我们便陷入了瓶颈,怎么化简呢?
别着急,我们看一看在证明引理的时候,我们的一行证明。
∑i=1p−1(2p−1)pi2p−2≡p(p+1)(modp2)
再看看
∑j=1p−1(2p−1)pj2p−2modp2
是不是很interesting!让我们来继续化简
2kp(p+1)+∑i=0k−1i∗p(p+1)modp2
2kp(p+1)+∑i=0k−1i∗pmodp2
2kp(p+1)+2k(k−1)∗pmodp2
然后就解出来了!
时间复杂度:O(1)(明显的)
代码(这里只给“打表”法)
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int main()
{
ll k,p;scanf("%lld%lld",&k,&p);
k%=p;
if(k==0) printf("0\n");
else{
if(p-k<k) k=p-k;
ll st=p-(p-1)/2,ed=p-(p-1)/2+k-1;
ll t=((st+ed)*k/2)%p;
printf("%lld\n",t*p);
}
return 0;
}