LA 4270 Discrete Square Roots (扩展欧几里得+模方程)

本文介绍了一种求解模n意义下离散平方根的方法,通过对给定的r²≡x(mod n)进行数学变换,利用扩展欧几里得算法解决直线模方程ax+by=2r′,并提供了C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LA 4270 Discrete Square Roots


题目大意:

在模n的意义下,非负整数x的离散平方根是满足0r<n的整数,所以一个x可能会有多个离散平方根.
输入x,n,r(1x<n,2n109,1rn),输出数据编号和所有离散平方根,从小到大排序.

题目分析:

(又是一道扩欧的题,orz……)

已知r2x(mod n),则有r2x=k1n,设r2x=k2n
所以r2r2=k3n,则有(r+r)(rr)=k3n

ab=n,所以

(r+r)(rr)=k3ab
r+ra(mod n),rrb(mod n)

(一开始的时候推导到这里就推不下去了,orz……)

r+r=ax,rr=by
(r+r)+(rr)=ax+by
ax+by=2r

得到一个直线模方程ax+by=2r,通过扩欧求解.
因为ab=n,所以枚举n的因子求解(详见代码).

代码:

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>

using namespace std;

typedef long long ll;

void exgcd(ll a,ll b,ll& g,ll& x,ll& y)
{
    if(!b) g=a,x=1,y=0;
    else exgcd(b,a%b,g,y,x),y-=x*(a/b);
}

ll x,n,r;
set<ll>ans;

void solve(ll a,ll b,ll c)//c=2r
{
    ll g,x,y;
    exgcd(a,b,g,x,y);//ax+by=gcd(a,c)
    if(c%g) return ;
    x*=c/g;//ax+by=c的一组解x0
    b/=g;//b'
    x=(x%b+b)%b;//x的非负整数解,x=x0+kb' 
    ll r=a*x-c/2;//r的一组解,可能为负 
    ll p=a*b;//p=a*b' 因为x=x0+k*b',r=ax+r'=k*a*b'+r'
    while(r<n) {
        if(r>=0) ans.insert(r);
        r+=p;
    }
}

int main()
{
    int kase=0;
    while(scanf("%lld%lld%lld",&x,&n,&r)==3&&n) {
        ans.clear();
        ll m=sqrt(n);
        for(ll i=1;i<=m;i++) if(n%i==0)
            solve(i,n/i,2*r),solve(n/i,i,2*r);
        printf("Case %d:",++kase);
        for(set<ll>::iterator it=ans.begin();it!=ans.end();it++)
            printf(" %lld",*it);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值