首先扩O:T了一个点(因为上界松),83分。
#include <cstdio> using namespace std; int n, p; void exgcd(int a, int p, int &b, int &x){ if (p==0){ b=1, x=0; return; } exgcd(p, a%p, b, x); int tmp=b; b=x; x=tmp-a/p*x; return; } int main(){ scanf("%d%d", &n, &p); int x, y; for (int i=1; i<=n; ++i){ exgcd(i, p, x, y); printf("%d ", (x+p)%p); } return 0; }
然后费马,事实证明果然更慢,上界很紧。
#include <cstdio> using namespace std; int n, p; int expower(int a, int pow, int mod){ int ans=1; while (pow){ if (pow&1) ans=1LL*ans*a%mod; a=1LL*a*a%mod; pow>>=1; } return ans; } int main(){ scanf("%d%d", &n, &p); for (int i=1; i<=n; ++i){ printf("%d ", expower(i, p-2, p)); } return 0; }
正解:首先$1^{-1} equiv 1 pmod p$
我们设:$p = kcdot i + r,~r < i,~1 < i < p$
将其放在模p意义下:$kcdot i + r equiv 0 pmod p$
两边同乘i-1,r-1就会得到:
$egin{eqnarray*} kcdot r^{-1} + i^{-1} &equiv& 0 &pmod p\ i^{-1} &equiv& -kcdot r^{-1} &pmod p\ i^{-1} &equiv& -leftlfloorfrac{p}{i} ight floorcdot left(pmod i ight)^{-1} &pmod p end{eqnarray*}$
于是核心代码就一行:
A[i] = -(p / i) * A[p % i];
我的代码:
注意:有可能是负数
#include <cstdio> using namespace std; const int maxn=3000000; int n, p, a[maxn]; int main(){ scanf("%d%d", &n, &p); a[1]=1; printf("%d ", a[1]); for (int i=2; i<=n; ++i){ a[i]=(1LL*-(p/i)*a[p%i])%p; a[i]=(a[i]+p)%p; printf("%d ", a[i]); } return 0; }