Modified LCS (扩展欧几里德)细写了对这个算法思路的理解

题目:Modified LCS

为过此题去仔细研究了下扩展欧几里德算法,领悟了一些精华。

模板为:

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

这里算出来的x,y是对于方程ax+by=gcd(a,b)而言的一组解。

为什么叫扩展欧几里德说明肯定用了欧几里德算法的原理即:gcd(a,b)=gcd(b,a%b);

ax+by=gcd(a,b)=gcd(b,a%b)=。。。可以一直使用欧几里德算法直到b=0,即就是刚才算法模板的第一句话,

if(!b) {d = a; x = 1; y = 0;} 

当b=0时,a = gcd(a,b),ax+by=gcd(a,b)这个方程就变为ax=a了,即x=1,y等于几其实是随便的,但是必须要有数字为了反推出之前的解,这里就为了简洁就等于0。PS:可以尝试不填0说不定靠点运气能提高效率(玩笑)。

然后得到了最后一组解(1,0)如何推出第一个方程的解呢?

显然可知:gcd(b,a%b) = bx+a%by。注意这里的 x和y跟第一个方程的x和y是不一样的。

连等式得:ax1 + by1 = bx2 + a%by2 = bx2 + (a - a/b*b)y2这里是利用取模的性质.即a%b = a - a/b*b。

交换位置得: ax1 + by1 = ay2 + b(x2 - a/b * y2);

因为是构造解所以根据恒等式设 x1=y2 ,y1 = (x2 - a/b * y2);

注意模板里第二句

else{ gcd(b, a%b, d, y, x); y -= x*(a/b);} 

x和y是交换位置的。就是因为 x1=y2,即上一层的 y是当前的x,当前gcd的y应该是上一层的x减去a/b×y。就是y1 = (x2
- a/b * y2);

但是在这

gcd(b, a%b, d, y, x);

之后。你上一层的x的值变成了当前y的值,上一层y的值变成了当前x的值。当前的x值就是这个,但是y值却不是上一层的x,需要计算,所以就有了

 y -= x*(a/b);

如果还有不懂可以拿笔模拟一下,先不停的递归直到终点即b==0时,然后给x,y赋值1和0,再一步一步回推执行 y -= x*(a/b);

好了。可以讲那道题了。题意就是2个等差序列,告诉你个数,起点,公差,问你有几个数是2个序列共有的?

此题就是要解F1 + D1x = F2 + D2y在0=<x<=N1-1 && 0=<y<=N2-1最多的整数解。(F为起点,D为公差,N为个数)

移项可得 D1x - D2y = F2 - F1一个标准的可用扩展欧几里德的方程。

唯一不同的是方程b的地方要用-D2,先用模板解出一个解x0,y0。

先设g = gcd(d1,d2)即最小公约数。

明确下思路,此题是要求最小且大于等于0的x和y,然后这个2个点就是起点了,其后一样的数就是起点加上2个序列公差的最小公倍数×k了。最小公倍数为d1*d2/g。

第一个序列相同数的间隔为最小公倍数除以d1,即p1 = d1*d2/g/d1 = d2/g,同理第二个序列相同数的间隔为p2 = d1/g。

故第一个序列可能的相同数个数为(N1 - 1 - x)/p1,第二个为(N1 - 1 - y)/p2。

答案为2个值的较小者。

刚才说的间隔就可以用来求方程的其他解,即x = x0 + k*p1,y = y0 + k*p2。

还要分2种情况来求x,y。

其实是2个方向,如果x0,y0有一个小于0,说明k要大于0,一直分别加p1,p2直到2者都大于等于0为止。

如果都大于0,则说明可能太大了,要求最小且大于等于0的x和y嘛,说明k要小于0。然后一直分别减p1,p2直到2者不能再减了,再减就有一项小于0为止。

具体思路已经非常清晰了,如果没有看懂希望多看几遍应该就能想通。

AC代码:

#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<ctime>
using namespace std;
#define ll long long 

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

int main()
{
    ll n1,f1,d1,n2,f2,d2;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld%lld%lld",&n1,&f1,&d1,&n2,&f2,&d2);
        ll x,y,g;
        gcd(d1,-d2,g,x,y);
        ll f = f2-f1;
        x *= f/g;//小心溢出
        y *= f/g;
        g = abs(g);
        ll a = d1/g;
        ll b = d2/g;
        if(x < 0 || y < 0)
        {
            while(x < 0 || y < 0)
            {
                x += b;
                y += a;
            }
        }
        else
        {
            while(x >= 0 && y >= 0)
            {
                x -= b;
                y -= a;
            }
            x += b;
            y += a;
        }
        ll num1 = (n1-1-x)/b;
        ll num2 = (n2-1-y)/a;
        printf("%lld\n",min(num1,num2)+1);
    }
    return 0;
} 

/**************************************************************
    Problem: 1446
    User: HNU_TEAM_3
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1484 kb
****************************************************************/

Modified LCS (扩展欧几里德)细写了对这个算法思路的理解,布布扣,bubuko.com

时间: 2024-12-27 13:41:43

Modified LCS (扩展欧几里德)细写了对这个算法思路的理解的相关文章

CSU 1446 Modified LCS 扩展欧几里得

要死了,这个题竟然做了两天……各种奇葩的错误…… HNU的12831也是这个题. 题意: 给你两个等差数列,求这两个数列的公共元素的数量. 每个数列按照以下格式给出: N F D(分别表示每个数列的长度,首项,公差). 思路: 先用扩展欧几里得得到两个数列的一个交点,然后求出两个数列的第一个交点.然后分别得到从第一个交点,到末项的可能交点数量. 假设 F1+K1*D1 = F2+K2*D2 是某一个交点, 移向得到 F1 - F2 = K2*D2 - K1*D1. 由扩展欧几里得定理的结论 x*

CSU - 1446 Modified LCS

Description Input Output Sample Input 3 5 3 4 15 3 1 10 2 2 7 3 3 100 1 1 100 1 2 Sample Output 4 3 50 题意:求两个等差序列相同的元素个数 思路: 首先我们可以假设得到解是当 F1 + D1 * K1 = F2 + D2 * K2,那么我们可以通过扩展欧几里德算法来求出最小的正数解,再来是当我们知道一组解是(x0, y0)的时候,任意解都可以是(x0 + kb', y0-ka') {b' = b

扩展欧几里德算法

文章来源:http://blog.csdn.net/zhjchengfeng5/article/details/7786595 谁是欧几里德?自己百度去 先介绍什么叫做欧几里德算法 有两个数 a b,现在,我们要求 a b 的最大公约数,怎么求?枚举他们的因子?不现实,当 a b 很大的时候,枚举显得那么的na?ve ,那怎么做? 欧几里德有个十分又用的定理: gcd(a, b) = gcd(b , a%b) ,这样,我们就可以在几乎是 log 的时间复杂度里求解出来 a 和 b 的最大公约数了

POJ1061——青蛙的约会(扩展欧几里德)

青蛙的约会 Description两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面.

HihoCoder - 1297 数论四&#183;扩展欧几里德

描述 小Hi和小Ho周末在公园溜达.公园有一堆围成环形的石板,小Hi和小Ho分别站在不同的石板上.已知石板总共有m块,编号为 0..m-1,小Hi一开始站在s1号石板上,小Ho一开始站在s2号石板上. 小Hi:小Ho,你说我们俩如果从现在开始按照固定的间隔数同时同向移动,我们会不会在某个时间点站在同一块石板上呢? 小Ho:我觉得可能吧,你每次移动v1块,我移动v2块,我们看能不能遇上好了. 小Hi:好啊,那我们试试呗. 一个小时过去了,然而小Hi和小Ho还是没有一次站在同一块石板上. 小Ho:不

【转】扩展欧几里德

http://blog.csdn.net/zhjchengfeng5/article/details/7786595 扩展欧几里德算法 谁是欧几里德?自己百度去 先介绍什么叫做欧几里德算法 有两个数 a b,现在,我们要求 a b 的最大公约数,怎么求?枚举他们的因子?不现实,当 a b 很大的时候,枚举显得那么的na?ve ,那怎么做? 欧几里德有个十分又用的定理: gcd(a, b) = gcd(b , a%b) ,这样,我们就可以在几乎是 log 的时间复杂度里求解出来 a 和 b 的最大

UVAlive 6763 Modified LCS

LCS stands for longest common subsequence, and it is a well known problem. A sequence in thisproblem means a list of integers, and a sequence X is considered a subsequence of another sequence Y ,when the sequence X can be obtained by deleting zero or

扩展欧几里德算法及其应用

接着欧几里德算法往后写,扩展欧几里德算法常常用来解不定方程及一些相关的应用,用到的思想就是欧几里德算法的思想:通过在结果不改变的情况下不断取余而逐步缩小数据规模,两个数会不断变小,直到减小到一个数是另一个数的倍数的时候,就很容易求出他们的最小公倍数了.下面我们来说说扩展欧几里德的思想: 我们要求出 a * x + b * y = c 的所有解,其中 a,b,c 是已经告诉你的常数,而 x,y 是待求的未知量,我们要求出所有的 x,y ,其实只要求出一组 x0,y0就行了,剩下的解可以由 x=x0

数论快速入门(同余、扩展欧几里德、中国剩余定理、大素数测定和整数分解、素数三种筛法、欧拉函数以及各种模板)

数学渣渣愉快的玩了一把数论,来总结一下几种常用的算法入门,不过鶸也是刚刚入门, 所以也只是粗略的记录下原理,贴下模板,以及入门题目(感受下模板怎么用的) (PS:文中蓝色字体都可以点进去查看百度原文) 附赠数论入门训练专题:点我打开专题(题目顺序基本正常,用以配套数论入门) 一.同余定理 简单粗暴的说就是:若 a-b == m 那么 a%m == b%m 这个模运算性质一眼看出...直接上入门水题: Reduced ID Numbers 附AC代码(这个也没啥模板....知道就好) #inclu