题目描述
The factorial of a natural number is the product of all positive integers less than or equal to it. For example, the factorial of 4 is 1 · 2 · 3 · 4 = 24. A faulty factorial of length n is similar to the factorial of n, but it contains a fault: one of the integers is strictly smaller than what it should be (but still at least 1). For example, 1 · 2 · 2 · 4 = 16 is a faulty factorial of length 4. Given the length n, a prime modulus p and a target remainder r, find some faulty factorial of length n that gives the remainder r when divided by p.
Input
The first line contains three integers n, p and r (2 ≤ n ≤ 1018 , 2 ≤ p < 107 , 0 ≤ r < p) — the length of the faulty factorial, the prime modulus and the target remainder as described in the problem statement.
Output
If there is no faulty factorial satisfying the requirements output “-1 -1”. Otherwise, output two integers — the index k of the fault (2 ≤ k ≤ n) and the value v at that index (1 ≤ v < k). If there are multiple solutions, output any of them.
Sample Input 1
4 5 1
Sample Output 1
3 2
Sample Input 2
4 127 24
Sample Output 2
-1 -1
题意
题意还挺好理解的,给三个数,n,p,r(p > r),在n的阶乘中找到一个数k(2<=k <= n),将k换成比k小的数v(1<=v<k),使得换完之后的阶乘结果res对p取模结果为r,即res≡r(mod p)。
例如第一个样例,n = 4,阶乘为1*2*3*4,但若把3换成2,阶乘变为1*2*2*4 = 16 ≡ 1 (mod 5)
输出任意一组k,v,若找不到这样一组k,v,输出-1 -1
思路
这道题最好是讨论n,p的大小。
①n>=2p时,不管修改哪一个值,得到的结果总是p的倍数,r只能为0,所以r = 0时,修改任意一个值(例如使2改为1)即可,r ≠ 0,输出-1 -1
②p<=n<2p时,若r = 0,则修改的一定不是p,找到任意一个不是p的值改为1即可,找不到输出-1 -1(例如n = 2,p = 2,找不到);若r ≠ 0,则修改的一定是p,至于修改成什么,可以枚举小于p的值,找到一个即可。
③n<p时,这时候用到数论的知识,根据res≡r(mod p),可以整理成v≡(mod p),p是素数,根据费马小定理,求逆元
v ≡ ((r * k % p) * Fast Power(n!, p-2, p)) % p ,枚举k,若得到的v>=1&&v<k,则找到一组,若找不到输出-1 -1
代码
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
ll fast_power(ll a, ll b, ll m)//快速幂
{
ll ans = 1;
a %= m;
while(b)
{
if(b&1) ans = ans *a % m;
a = a * a % m;
b >>= 1;
}
return ans;
}
int main()
{
ll n,p,r,v;
bool flag = false;
scanf("%lld %lld %lld", &n, &p, &r);
if(n >= 2 * p)
{
if(r == 0)
printf("2 1\n");
else
printf("-1 -1\n");
}
else if(n >= p && n < 2 * p)
{
if(r == 0)
{
for(ll i = 2; i <= n; i++)
{
if(i != p)//只要能找到不是p的k就可
{
printf("%lld 1\n", i);
flag = true;
break;
}
}
if(!flag)
printf("-1 -1\n");
}
else
{
ll jc = 1;
for(ll i = 2; i <= n; i++)
{
if(i == p) continue;
jc = (jc * (i % p)) % p;
}
for(ll i = 1; i < p; i++)//将k换成i
{
if((jc * (i % p)) % p == r)
{
printf("%lld %lld\n", p, i);
flag = true;
}
}
if(!flag)
printf("-1 -1\n");
}
}
else
{
ll jc = 1;
for(ll i = 2; i <= n; i++)
jc = (jc * (i % p)) % p;
jc = fast_power(jc, p - 2, p);//求阶乘的逆元
for(ll i = 2; i <= n; i++)
{
v = (((r % p) * (i % p)) % p * jc) % p;
//printf("%lld\n", y);
if(v >= 1 && v < i)
{
printf("%lld %lld\n", i, v);
flag = true;
break;
}
}
if(!flag)
printf("-1 -1\n");
}
//printf("%lld %lld %lld", n, p, r);
return 0;
}
如有错误请指明~ ฅ●ω●ฅ