/***********************************************************************/ | 求 1^(p-1) + 2^(p-1) + ………… + n^(p-1) mod p | 思路: 由费马小引理 a^p mod p = 1 (p is a prime number) | 并由模运算性质 (a+b+c)mod n = a%n + b%n + c | 因此找到小于n 的第一个素数 pn 则 从{ 1^(p-1) ……+ pn^(p-1) }mod p = 1 | 再用反复平方法计算pn+1 至 n之间的所有幂(p-1) 模 p 的值 最后再加上1 - pn | 项的 1, 最后mod p 即为结果 /************************************************************************/ #include<iostream> #include<cmath> using namespace std; const int maxn = 10001; bool isprime[maxn]; int prime[1230]; //涮素数1-n int getprime(int n) { int i, j, k = 0; int s, e = (int)sqrt(n*1.0) + 1; memset(isprime, true, sizeof(isprime)); isprime[0] = isprime[1] = false; prime[k++] = 2; for(i=4; i<n; i+=2) isprime[i] = false; for(i=3; i<n; i+=2) { if(isprime[i]) { prime[k++] = i; for(s=i*2, j=i*i; j<n; j+=s) { isprime[j] = false; } } } for(; i<n; i+=2) { if(isprime[i]) prime[k++] = i; } return k; } int find_prime(int n, int k) { for(int i=0; i<k; i++) { if(prime[i] > n) return i; } return 0; } int mod_exp(int a, int p, int m) { if(a > m) a %= m; int i, d = 1, b[35]; for(i=0; i<35; i++) { b[i] = p%2; p /= 2; if(p==0) break; } for(; i>=0; i--) { d = (d*d)%m; if(b[i]==1) d = (d*a)%m; } return d; } int solve(int n, int p, int k) { int ret = 1;//前 1 到 pn 项mod p后为1 int pos = find_prime(n, k); for(int i=prime[pos]; i<=n; i++) { int d = mod_exp(i, p-1, p); ret += d; ret %= p; } return ret; } int main() { int k = getprime(maxn); printf("%d/n", k); int n, p;//p must be prime number while(scanf("%d%d", &n, &p)!=EOF) { if(n==0) break; int ret = solve(n, p, k); printf("%d/n", ret); } return 0; } 此程序由于筛出来的是小范围的素数,所以如果n太大时是不行的,就要从 n 倒着用暴力解决了。可能还会有其他的方法,不过才疏学浅…… 不过发现多数数据都是1 啊,没找到其他的值