牛客编程巅峰赛S1第12场 王者C-椭圆曲线(快速乘的运用)

题目链接:https://ac.nowcoder.com/acm/contest/6916/C
CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/108035320

题目描述
椭圆曲线加密算法是在椭圆曲线有限域上进行加密的算法,一般的椭圆曲线为\(E_{p}(a,b): y^2=x^3+ax+b\),其中p为质数。
椭圆曲线上的点的运算满足以下规则:
1.曲线上A、B不同两点相加,过A、B两点画一条直线,找到直线与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A+B,即为加法。如下图所示:A + B = C

2.相同点A与A相加,过A点做切线,与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A + A,即2A,即为二倍运算。

\(E_{p}(a,b): y^2=x^3+ax+b\)\(P(x_1,x_2),Q(x_2,y_2),R(x_3,y_3)\),其中R=P+Q,有
\(x_3\equiv k^2-x_1-x_2\: (mod\: p)\)
\(y_3\equiv k(x_1-x_3)-y_1\: (mod\: p)\)
若P=Q,则\(k=\frac{3x_1^2+a}{2y_1}\: (mod\: p)\)
\(P\neq Q\),则\(k=\frac{y_2-y_1}{x_2-x_1}\: (mod\: p)\)
现有\(E_p(1,1)\),其中p=1000000007,牛牛得到了点\(P(x_1,y_1)\),你能告诉她\(\ nP\)是多少吗。

输入
(0,1),3

输出
(72,611)

备注:
\(0\leq x_1,y_1\leq 10^9\)\(1\leq n\leq 10^9\)

题目的意思是让你求\(P+P+P+P+...+P\)的值,而这些运算可以通过上面的公式得到,只不过有点伤人的是,n的范围在\(1e9\),所以我们不能直接暴力地一个一个加,那么我们可以想到快速乘(实际上本质是个加法运算),这个东西就很方便了。。。只不过它满不满足快速乘就不太清楚了,只不过可以冲一波。然后就愉快地发现。。。A了。

以下是AC代码:

/**
 * struct Point {
 *	int x;
 *	int y;
 * };
 */
typedef long long ll;
const int mod=1e9+7;

class Solution {
public:
    /**
     * 
     * @param P Point类 
     * @param n int整型 
     * @return Point类
     */
    ll qpow(ll a,ll b){
        ll ans=1;
        a%=mod;
        while (b){
            if (b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ans;
    }
    
    ll pw(ll x) {return x*x%mod;}
    
    Point Plus(Point a,Point b)
    {
        ll x1=a.x,x2=b.x,y1=a.y,y2=b.y;
        if (x1==x2 && y1==y2){
            ll k=(3LL*pw(x1)+1)%mod*qpow(2LL*y1,mod-2)%mod;
            int x3=(pw(k)-((x1+x2)%mod)+mod)%mod;
            int y3=(k*(x1-x3+mod)%mod-y1+mod)%mod;
            return Point{x3,y3};
        }
        else {
            ll k=(y2-y1+mod)%mod*qpow((x2-x1+mod),mod-2)%mod;
            int x3=(pw(k)-((x1+x2)%mod)+mod)%mod;
            int y3=(k*(x1-x3+mod)%mod-y1+mod)%mod;
            return Point{x3,y3};
        }
    }
    
    Point multi(Point a,int b)
    {
        Point ans=a;
        b--;
        while (b){
            if (b&1) ans=Plus(ans,a);
            a=Plus(a,a);
            b>>=1;
        }    
        return ans;
    }
    
    Point NTimesPoint(Point P, int n) {
        return multi(P,n);
    }
};
posted @ 2020-08-16 13:31  lonely_wind  阅读(219)  评论(0)    收藏  举报