[JOI精進録] 難易度7「fermat」(2007年日本情報オリンピック 春合宿3-2)
問題リンク
問題概要
を満たす の組はいくつ考えられますか?
解説
AC解法1 (100/100点)
繰り返し二乗法を使ってで乗の数をで割ったあまりを列挙し、
乗してで割ったあまりがになるの数
を数え上げます。
とについてを全探索すると、は定数時間で求められるためで答えることができます。
ACコード1
#include <bits/stdc++.h> using namespace std; int main(){ int p,n; cin >> p >> n; long long r(0); vector<int> A(p); for (int i(0);i < p;++i){ int r = 1; for (int t = n,u = i;t;t>>=1,u*=u,u%=p) if ((t&1)) r*=u,r%=p; ++A[r]; } for (int i(0);i < p;++i) for (int k(0);k < p;++k){ r += A[i]*A[k]*A[(i+k)%p]; } cout << r << endl; }
提出結果1
AC解法2(1より高速) (100/100点)
を1では全探索したところでFFTです。ACLに定義されているのを使うと簡単に実装できます。
ACコード2
#include <bits/stdc++.h> #include <atcoder/convolution> using namespace std; int main(){ #define int long long int p,n,r; cin >> p >> n; vector<int> A(p); for (int i(0);i < p;++i){ r = 1; for (int t = n,u = i;t;t>>=1,u*=u,u%=p) if ((t&1)) r*=u,r%=p; ++A[r]; } vector<int> B = atcoder::convolution_ll(A,A); for (int i(0);i < B.size();++i) B[i]*=A[i%p]; cout << accumulate(B.begin(),B.end(),0ll) << endl; }