hiho一下 第九十七周 题目1 : 数论六·模线性方程组

传送门

题目1 : 数论六·模线性方程组

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

小Ho:今天我听到一个挺有意思的故事!

小Hi:什么故事啊?

小Ho:说秦末,刘邦的将军韩信带领1500名士兵经历了一场战斗,战死四百余人。韩信为了清点人数让士兵站成三人一排,多出来两人;站成五人一排,多出来四人;站成七人一排,多出来六人。韩信立刻就知道了剩余人数为1049人。

小Hi:韩信点兵嘛,这个故事很有名的。

小Ho:我觉得这里面一定有什么巧妙的计算方法!不然韩信不可能这么快计算出来。

小Hi:那我们不妨将这个故事的数学模型提取出来看看?

小Ho:好!

<小Ho稍微思考了一下>

小Ho:韩信是为了计算的是士兵的人数,那么我们设这个人数为x。三人成排,五人成排,七人成排,即x mod 3, x mod 5, x mod 7。也就是说我们可以列出一组方程:

x mod 3 = 2
x mod 5 = 4
x mod 7 = 6

韩信就是根据这个方程组,解出了x的值。

小Hi:嗯,就是这样!我们将这个方程组推广到一般形式:给定了n组除数m[i]和余数r[i],通过这n组(m[i],r[i])求解一个x,使得x mod m[i] = r[i]。

小Ho:我怎么感觉这个方程组有固定的解法?

小Hi:这个方程组被称为模线性方程组。它确实有固定的解决方法。不过在我告诉你解法之前,你不如先自己想想怎么求解如何?

小Ho:好啊,让我先试试啊!

提示:模线性方程组

输入

第1行:1个正整数, N,2≤N≤1,000。

第2..N+1行:2个正整数, 第i+1行表示第i组m,r,2≤m≤20,000,000,0≤r<m。

计算过程中尽量使用64位整型。

输出

第1行:1个整数,表示满足要求的最小X,若无解输出-1。答案范围在64位整型内。

样例输入
3
3 2
5 3
7 2
样例输出
23

解题思路:

就是解一个模线性方程组,只要扩展欧几里得算法会了,这个应该是不是什么问题。大多数在hiho里面都提示了,在这里我就不赘述了,只提供一下AC代码:

My Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e3+5;
void Ex_gcd(LL a, LL b, LL &x, LL &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return ;
    }
    LL x1, y1;
    Ex_gcd(b, a%b, x1, y1);
    x = y1;
    y = x1-(a/b)*y1;
}
LL GCD(LL a, LL b)
{
    if(b == 0)
        return a;
    return GCD(b, a%b);
}
LL m[MAXN],r[MAXN], n;
LL Solve()
{
    LL M = m[1], R = r[1], d, k1, k2, c;
    for(int i=2; i<=n; i++)
    {
        d = GCD(M, m[i]);
        c = r[i] - R;
        if(c % d)
            return -1;
        Ex_gcd(M/d, m[i]/d, k1, k2);
        k1 = (c/d*k1)%(m[i]/d);
        R = R+k1*M;
        M = M/d*m[i];
        R %= M;
    }
    if(R < 0)
        R = R+M;
    return R;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; i++)
            scanf("%lld%lld",&m[i],&r[i]);
        LL ret = Solve();
        printf("%lld\n",ret);
    }
    return 0;
}
时间: 2024-10-20 09:46:58

hiho一下 第九十七周 题目1 : 数论六·模线性方程组的相关文章

hihoCoder 1303 数论六&#183;模线性方程组

Description 求解模线性方程组, \(m_i\) 不互质. Sol 扩展欧几里得+中国剩余定理. 首先两两合并跟上篇博文一样. 每次通解就是每次增加两个数的最小公倍数,这对取模任意一个数都是0. 伪代码如下 M = m[1], R = r[1] For i = 2 .. N d = gcd(M, m[i]) c = r[i] - R If (c mod d) Then // 无解的情况 Return -1 End If (k1, k2) = extend_gcd(M / d, m[i]

Eular质数筛法-hiho一下 第九十三周

Eular质数筛法 hihocoder第九十三周 输入 第1行:1个正整数n,表示数字的个数,2≤n≤1,000,000. 输出 第1行:1个整数,表示从1到n中质数的个数 c++代码 #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <qu

hiho一下 第二十三周---题目1 : 最短路径&#183;一

题目1 : 最短路径·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的早上,小Hi和小Ho在经历了一个小时的争论后,终于决定了如何度过这样有意义的一天--他们决定去闯鬼屋! 在鬼屋门口排上了若干小时的队伍之后,刚刚进入鬼屋的小Hi和小Ho都颇饥饿,于是他们决定利用进门前领到的地图,找到一条通往终点的最短路径. 鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道

hihoCoder - hiho一下 第二十七周 - A - 最小生成树二&#183;Kruscal算法

题目1 : 最小生成树二·Kruscal算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了--但是幸运的是,经过计算机的分析,小Hi已经筛选出了一些比较适合建造道路的路线,这个数量并没有特别的大. 所以问题变成了--小Hi现在手上拥有N座城市,且已知其中一些城市间建造道路的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需

hihocode 九十七周 中国剩余定理

题目1 : 数论六·模线性方程组 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho:今天我听到一个挺有意思的故事! 小Hi:什么故事啊? 小Ho:说秦末,刘邦的将军韩信带领1500名士兵经历了一场战斗,战死四百余人.韩信为了清点人数让士兵站成三人一排,多出来两人:站成五人一排,多出来四人:站成七人一排,多出来六人.韩信立刻就知道了剩余人数为1049人. 小Hi:韩信点兵嘛,这个故事很有名的. 小Ho:我觉得这里面一定有什么巧妙的计算方法!不然韩信不可能这么快计

hiho一下 第150周 -- Demo Day (DP)

hiho一下 第150周 -- Demo Day (DP) 题目1 : Demo Day 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 You work as an intern at a robotics startup. Today is your company's demo day. During the demo your company's robot will be put in a maze and without any information

第十七周周总结 Swing

考试系统 1.登录功能 用户和密码存在在哪里? 文件 2.考试功能 考试题目和答案存在哪? 文件 3.展示功能 GUI Graphical User Interface图形用户接口 #GUI Java集合 String I/O 文件 c--->桌面应用程序 c/s--->client Server 客户端/服务器 QQ *B/S-->Browser Server 浏览器/服务器 淘宝 GUI Graphical User Interface 图形用户接口 就是采用图形的方式,进行操作页面

软件工程第十七周学习进度条

时间 学习花费时间 (小时) 代码量(行) 博客量(篇) 了解到的知识点 不足 第十七周 周一 (8.00-9.50)上课 周三.周四下午:继续团队项目,完成团队项目的相关作业 215 4    

hiho一下 第二十一周(线段树 离散化)

知识点1:离散化  对于这些区间来说,其实并不会在乎具体数值是多少,而是在他们的左右端点之间互相进行比较而已.所以你就把这N个区间的左右端点——2N个整数提出来,处理一下呗?你要注意的是,这2N个数是什么其实并不重要,你可以把这2N个数替换成为任何另外2N个数,只要他们之间的相对大小关系不发生改变就可以.” 解决方法: 那么我需要额外做的事情就是在构建线段树之前对区间进行预处理:将区间的左右端点选出来,组成一个集合,然后将这个集合依次对应到正整数集合上,并且利用这个对应将原来的区间的左右端点更换