给定n,质数p和一个目标余数r
你需要改变n的阶乘中的一个数字,使得其积模p余r。
感觉不能融会贯通
我以为是个EXGCD的神仙题
首先n看似很大,但是明显n并不是完全有用
时若余数不为0则无解
对于有:
这个明显是一个不定方程,算出最小解再判断和p的大小关系就好了
但是怎么办?
由于这个不超过1e7我认为直接枚举变的暴力EXGCD
但很明显这是不能A掉的(虽然开了3s)
这个时候思考BSGS(北上广深新一线算法)
我们有一个在同余方程移位的操作
等价于
如果线性预处理逆元这是O1查询的
那么就A了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
LL n,p,r;
LL Check(LL Id,LL sum,LL mod){
LL ret=1;
for(int i=1;i<=n;++i){
if(i==Id)ret=ret*sum%mod;
else ret=ret*i%mod;
}
return ret;
}
void Solve50(){
for(int i=2;i<=n;++i){
for(int j=1;j<i;++j){
if(Check(i,j,p)==r){
cout<<i<<" "<<j;
return;
}
}
}
cout<<-1<<" "<<-1;
}
void EXGCD(LL &x,LL &y,LL A,LL B){
if(B==0){
x=1;
y=0;
return;
}
else{
EXGCD(x,y,B,A%B);
LL tmp=x;
x=y;
y=tmp-(A/B)*y;
}
}
const int N=1e7+10;
LL F[N];
void Solve100(){
if (n == p) {
if (r == 0) {
if (n == 2) cout << -1 << " " << -1 << endl;
else cout << 2 << " " << 1 << endl;
return;
}
else {
for (LL i=1; i<p; i++) if (i*(p-1)%p==r) {
cout << p << " " << i << endl;
return;
}
cout << -1 << " " << -1 << endl;
return;
}
}
if(n>=2*p){
if(!r)cout<<p+1<<" "<<1;
else cout<<-1<<" "<<-1;
return;
}
F[0]=1;
if(p>n){
LL x,y;
if(!r){
cout<<-1<<" "<<-1<<'\n';
return ;
}
for(int i=1;i<=n;++i){
F[i]=F[i-1]*i%p;
}
EXGCD(x,y,F[n],p);
LL Inv=(x+p)%p;
for(int i=2;i<=n;++i){
LL tmp=Inv*i%p*r%p;
if(tmp<i&&tmp){
cout<<i<<" "<<tmp<<'\n';
return;
}
}
cout<<-1<<" "<<-1;
}
else{
if(!r){
cout<<p+1<<" "<<1<<'\n';
return;
}
LL sum=1;
for(int i=1;i<=n;++i){
if(i==p)continue;
sum=sum*i%p;
}
LL x,y;
EXGCD(x,y,sum,p);
x=(x+p)%p;
if(x*r%p<=p){
cout<<p<<" "<<x*r%p;
}
else cout<<-1<<" "<<-1;
}
}
int main(){
// freopen("f.in","r",stdin);
// freopen("f.out","w",stdout);
cin>>n>>p>>r;
if(n<=500){
Solve50();
}
else{
Solve100();
}
return 0;
}