【数论+思维】 GYM101620F Faulty Factorial

http://codeforces.com/gym/101620/attachments

给你n,p,r,(1<=n<=1e18,p是<=1e7的质数,r<p)

n!中任选一个数换成比此数小的数,要求得到的新的乘积%p==r,问是否可以

不可以输出 -1 -1,可以输出 a b,(把a换成b)

分类讨论

1、r==0,如果r==0,

    (1) 当n<=2||n<p 1-n中没有p,那么改后的n!%p 一定不为0,  输出 -1 -1

    (2) 否则 将除p之外的数改掉就行

2、 r!=0

    (1)n>=2*p   因为1*2*……p*(p+1)*……2p*……*n  %p ==0(不管怎么改,都不可能使余数不为0)  输出 -1 -1

    (2)n>=p&&n<2*p   因为1*2*……p*……*n  %p ==0(只要把p改了,for循环,看1-p-1,哪个符合,输出即可)

    (3)n<p    寻找a,b 满足 n!*(b/a)%p==r   --->  n!*b%p=r*a --->   b=r*a*inv[n!]%p   遍历a,看b符不符合b<a,符合输出即可

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll quickpow(ll x,int n,int mod)
{
    ll res=1;
    while(n>0)
    {
        if(n&1) res=1LL*res*x%mod;
        x=1LL*x*x%mod;
        n>>=1;
    }
    return res;
}

int main()
{
    ll n;
    int p,r;
    int flag=0;
    scanf("%lld%d%d",&n,&p,&r);
    if(r==0)
    {
        if(n<=2||n<p)
            printf("-1 -1\n");
        else
            printf("%d 1\n",2+(p==2));
        return 0;
    }
    else
    {
        if(n>=2*p) printf("-1 -1\n");
        else if(n>=p&&n<2*p)
        {
            ll ans=1;
            for(int i=1;i<=n;i++)
            {
                if(i!=p) ans=ans*i%p;
            }
            for(int i=1;i<p;i++)
            {
                if(ans*i%p==r)
                {
                    printf("%d %d\n",p,i);
                    return 0;
                }
            }
            printf("-1 -1\n");
        }
        else
        {
            ll ans=1;
            for(int i=1;i<=n;i++)
            {
                ans=ans*i%p;
            }
            ll inv=quickpow(ans,p-2,p);
            for(int i=1;i<=n;i++)
            {
                ll b=1LL*r*i%p*inv%p;
                if(b<i)
                {
                    printf("%d %lld\n",i,b);
                    return 0;
                }
            }
            printf("-1 -1\n");
        }
        return 0;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值