标准解释:
考虑一条以(0,0)(0,0)为起点,(x,y)(x,y)为终点的线段上格点的个数(不包含端点时),
一定是gcd(x,y)-1gcd(x,y)−1,这个很显然吧.
然后整个网格图范围内的格点数目是\frac {q*(q-1)} 22(q-1)∗(q−2).
所以答案就是\frac {q*(q-1)} 2 -2q-1)∗(q−2)− 所有线段上的格点的个数.
因为gcd(a,b)=gcd(a,b-a)\ (b>a)gcd(a,b)=gcd(a,b−a) (b>a),
所以gcd(x,y)=gcd(x,p-x)=gcd(x,p)gcd(x,y)=gcd(x,p−x)=gcd(x,p),p是质数,所以gcd(x,y)=1gcd(x,y)=1,
所以线段上都没有格点,所以答案就是\frac {q*(q-1)} 22q-1)∗(q−2).
比赛的时候我是通过画图然后递推退出来这个结果的。
接下来就是求((q-1)*(q-2)/2) % p 了,并且,这个都不是质数。
有套路的,看代码。
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; #define LL long long #define INF 0x3f3f3f3f3 LL multiply(LL n , LL m , LL mod) { LL sum = 0 ; while(m) { if(m&1) { sum += n ; sum %= mod ; } m >>= 1 ; n *= 2 ; n %= mod ; } return sum ; } int main() { int t ; LL q,p ; scanf("%d",&t); while(t--) { scanf("%I64d%I64d",&q,&p) ; printf("%I64d\n",multiply((q-1),(q-2),2*p)/2) ; } return 0 ; }