B . Quadratic equation(二次剩余) 2019暑期牛客多校

题目链接:

    https://ac.nowcoder.com/acm/contest/889/B?&headNav=acm

题目思路:

     注意到 0 <= x <= y <= p ,很明显有两种情况,一种是x+y = b,一种是x + y = p + b 。

     那么我们先讨论x+y=c的情况,此时有 y = b - x 。

     带入 x * y % p = c ,可知 x(b-x)= k * p + c ,可以发现是一个二次函数,而且对称轴等于 b / 2 , 所以可以看出这种情况下,x

和y是关于b/2对称的,我们可以设这个距离是dis。

                                                               (\frac{b}{2}+dis)*(\frac{b}{2}-dis) = c (mod p)

此时出现了分数,那么方程两边同时乘以4, 通过拆项、移项可以得到

                                                          4*dis^{2} = (b^{2}-4c-4kp)mod (p)

此时可以二次剩余求出2*dis  ,  那么就可以求出两个答案了。

有一种特殊情况就是b*b==4*c 的情况,这种情况回到最原始的方程可以得出一定是0,那么就可以了。

还有上边提到了x+y=p+b的情况,其实细心观察这种情况和上边的情况重了,因为加上那个p最后也会被模掉。

(以后我再忘记乘逆元我就是傻逼)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9+7;
ll pow_mod(ll a,ll b, ll mod)
{
    ll ans=1;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
ll modsqr(ll a,ll n)
{
    ll b,k,i,x;

    if(n==2)return a%n;
    if(pow_mod(a, (n-1)/2 , n)==1){
        if(n % 4 == 3)
            x=pow_mod(a, (n+1)/4 ,n);
        else{
            for(b=1 ; pow_mod(b, (n-1)/2 ,n )==1 ;b++);
            i=(n-1)/2;
            k=0;
            do{
                i /=2;
                k /=2;
                if( (pow_mod(a,i,n) * (ll)pow_mod(b,k,n)+1 )% n ==0 )
                    k+=(n-1)/2;
            }
            while(i%2==0);
            x = (pow_mod(a,(i+1)/2,n) * (ll)pow_mod(b,k/2,n) )%n;
        }
        if(x*2 > n)
            x=n-x;
        return x;
    }
    return -1;
}
int main()
{
    int t;
    scanf("%d",&t);
    ll inv2=pow_mod(2,mod-2,mod);
    while(t--)
    {
        ll b,c;
        scanf("%lld%lld",&b,&c);
        ll res = b;
        ll now = (((res*res)%mod - 4*c)%mod + mod )%mod ;
        ll ans = modsqr(now,mod);
       // cout<<now<<endl;
        ll ret = (res - ans+mod)%mod;
        if((b*b-4*c)%mod==0){
            printf("%lld %lld\n",b/2,b/2);
            continue;
        }
        if(ans != -1){
            printf("%lld %lld\n",min(ret*inv2%mod,(res-(ret*inv2%mod)+mod)%mod),max(ret*inv2%mod,(res-(ret*inv2%mod)+mod)%mod) );
            continue;
        }
        printf("-1 -1\n");
    }
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值