Modular arithmetic and Montgomery form 实现快速模乘

题目:

电音之王



题解:

求数列前n项相乘并取模



思路:

①、这题的乘法是爆long long的,可以通过快速幂的思想去解决(按数位对其中的一个数进行剖分)。当然你的乘法会多出一个log的复杂度...

②、O(1)快速乘:一种O(1)复杂度求解整数相乘取模的思路(它对于64位的整型也是适用的):

  来自2009年国家集训队论文:骆可强:《论程序底层优化的一些方法与技巧》 (参考中附原文链接)

typedef long long ll;
#define MOL 123456789012345LL

inline ll mul_mod_ll(ll a,ll b)
{
    ll d = (ll)floor(a * (double)b / MOL + 0.5);
    ll ret = a * b - d * MOL;
    if(ret < 0) ret += MOL;
    return ret;
}

③、正解dls一句话题解(当然是看不懂了...)

  参考中附一篇Montgomery Modular Multiplication的博客(当然也是看不懂了...日文)

题解:(dls的代码)

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head

typedef unsigned long long u64;
typedef __int128_t i128;
typedef __uint128_t u128;
int _,k;
u64 A0,A1,M0,M1,C,M;

struct Mod64 {
    Mod64():n_(0) {}
    Mod64(u64 n):n_(init(n)) {}
    static u64 init(u64 w) { return reduce(u128(w) * r2); }
    static void set_mod(u64 m) {
        mod=m; assert(mod&1);
        inv=m; rep(i,0,5) inv*=2-inv*m;
        r2=-u128(m)%m;
    }
    static u64 reduce(u128 x) {
        u64 y=u64(x>>64)-u64((u128(u64(x)*inv)*mod)>>64);
        return ll(y)<0?y+mod:y;
    }
    Mod64& operator += (Mod64 rhs) { n_+=rhs.n_-mod; if (ll(n_)<0) n_+=mod; return *this; }
    Mod64 operator + (Mod64 rhs) const { return Mod64(*this)+=rhs; }
    Mod64& operator -= (Mod64 rhs) { n_-=rhs.n_; if (ll(n_)<0) n_+=mod; return *this; }
    Mod64 operator - (Mod64 rhs) const { return Mod64(*this)-=rhs; }
    Mod64& operator *= (Mod64 rhs) { n_=reduce(u128(n_)*rhs.n_); return *this; }
    Mod64 operator * (Mod64 rhs) const { return Mod64(*this)*=rhs; }
    u64 get() const { return reduce(n_); }
    static u64 mod,inv,r2;
    u64 n_;
};
u64 Mod64::mod,Mod64::inv,Mod64::r2;

u64 pmod(u64 a,u64 b,u64 p) {
    u64 d=(u64)floor(a*(long double)b/p+0.5);
    ll ret=a*b-d*p;
    if (ret<0) ret+=p;
    return ret;
}

void bruteforce() {
    u64 ans=1;
    for (int i=0;i<=k;i++) {
        ans=pmod(ans,A0,M);
        u64 A2=pmod(M0,A1,M)+pmod(M1,A0,M)+C;
        while (A2>=M) A2-=M;
        A0=A1; A1=A2;
    }
    printf("%llu\n",ans);
}

int main() {
    for (scanf("%d",&_);_;_--) {
        scanf("%llu%llu%llu%llu%llu%llu%d",&A0,&A1,&M0,&M1,&C,&M,&k);
        Mod64::set_mod(M);
        Mod64 a0(A0),a1(A1),m0(M0),m1(M1),c(C),ans(1),a2(0);
        for (int i=0;i<=k;i++) {
            ans=ans*a0;
            a2=m0*a1+m1*a0+c;
            a0=a1; a1=a2;
        }
        printf("%llu\n",ans.get());
    }
}



参考:

论程序底层优化的一些方法与技巧

除算?剰余算の高速化

原文地址:https://www.cnblogs.com/solvit/p/9747077.html

时间: 2024-11-05 22:01:18

Modular arithmetic and Montgomery form 实现快速模乘的相关文章

【分治】快速模幂

问题 R: [分治]快速模幂 时间限制: 1 Sec  内存限制: 64 MB提交: 8  解决: 7[提交][状态][讨论版] 题目描述 试求ab%n的值,其中a.b.n均为整数范围内的数. 输入 三个整数a.b和n 输出 ab%n的值 样例输入 1 1 1 样例输出 0解题思路:快速模幂比快速幂多了取余,和另一个快速取余是一样的.有公式.代码: #include <iostream> #include <cstdio> using namespace std; //a*b %

快速模幂

问题 H: [分治]快速模幂 时间限制: 1 Sec  内存限制: 64 MB提交: 79  解决: 64[提交] [状态] [讨论版] [命题人:admin] 题目描述 试求ab%n的值,其中a.b.n均为整数范围内的数. 输入 三个整数a.b和n 输出 ab%n的值 样例输入 1 1 1 样例输出 0 1 #include <iostream> 2 3 using namespace std; 4 typedef long long ll; 5 ll fun(ll a, ll b, ll

UVA11029 Leading and Trailing【快速模幂+数学】

Apart from the novice programmers, all others know that you can't exactly represent numbers raised to some high power. For example, the C function pow(125456, 455) can be represented in double data type format, but you won't get all the digits of the

模算术 modular arithmetic

https://en.wikipedia.org/wiki/Modular_arithmetic#Integers_modulo_n 模算术: 整数达到特定值时会' 折返 ' 回来-- 模数 modulus(moduli) 例如: 时钟 modulo 12. 且根据定义, 12 不仅和12一致,还和0一致. 模 n 就是除数为 n 的意思. 1. 定义同余关系 如果  a-b=kn   那么说 a,b 是模n同余的.n为正整数,k为整数. a≡b (mod n) n为同余的模数. 同余关系写为:

poj1845 逆元,快速模幂

题目大意: 给定两个正整数和,求的所有因子和对9901取余后的值. 分析: 很容易知道,先把分解得到,那么得到,那么 的所有因子和的表达式如下 因为要取模且存在除法,所以要用到逆元. 对于正整数和,如果有,那么把这个同余方程中的最小正整数解叫做模的逆元. 逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为. 推导过程如下 求现在来看一个逆元最常见问题,求如下表达式的值(已知) 当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果是素数,还可以用费马小定理.

快速模取幂

数论计算中经常出现的一种运算就是求一个数的幂ab对另外一个数n个模的运算,即计算: ab mod n (a,b,n是正整数) 由于计算机只能表示有限位的整数,所以编程时模取幂的运算要注意值的大小范围,当ab的值超过整数范围时,mod运算便无法进行. 如何解决这个问题,我们引出一个能计算ab mod n的值的有用算法--反复平方法,首先我们必须明确: d=ab mod n=(-((((a mod n)*a)mod n)*a)mod n-*a)mod n    {共b个a} 由此可以引出一个迭代式

组合数取模(转载)

本文转自:http://blog.csdn.net/skywalkert/article/details/52553048 0. 写在前面 在程序设计中,可能会碰到多种类型的计数问题,其中不少涉及到组合数的计算,所以笔者写下这么一篇文章,期望能解决一些常规的组合数求模问题.以下部分内容改编自AekdyCoin的<组合数求模>,而且为了感谢他对(懵懂的)笔者的启发,这篇文章的标题与其文章相同.另外,感谢Picks将多项式运算的技巧在中国进行推广,感谢51nod提供了许多有趣的数论题目,感谢fot

bnu 34985 Elegant String(矩阵快速幂+dp推导公式)

Elegant String Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Type: None None Graph Theory      2-SAT     Articulation/Bridge/Biconnected Component      Cy

JavaScript之form表单的序列化和json化[form.js]

一.应用场景 form提交时,使用ajax提交. 二.效果 通过本工具,实现表单所有form的快速序列化和json化,使前端人员在ajax提交form表单的时,脱离重复性的,大劳动量的手动抽取form属性和对应的值. 三.源码[form.js] //将数据序列化成 url请求方式的编码 function serialize(form){ var len=form.elements.length;//表单字段长度;表单字段包括<input><select><button>