POJ 2115C Looooops[一元线性同余方程]

一元线性同余方程

定义:

$a$,$b$是整数,$m$是正整数,形如

                            $ax\equiv b\,(mod\, m)$

且$x$是未知数的同余式称作一元线性同余方程。

对于方程$ax\equiv b\,(mod\, m)$, 可以把它写成二元一次不定式$ax+my=b$。要想方程有解,必须满足$(a,m)\mid d$。 这时利用扩展欧几里得求出$ax+my=(a,m)$

的一个特解,在乘上$b/(a,m)$就是我们所要的一个特解。

利用公式:

$ax_0+my_0=d=ax+my\Rightarrow a(x-x_0)+m(y-y_0)=0$

$(\frac{a}{(a,m)}, \frac{m}{(a,m)}) = 1 $

$x = x_0-\frac{m}{(a,m)}t$

这样就得到了$x$的所有解,其中最小的整数解是$ (x\,mod\,\frac{m}{(a,m)}+\frac{m}{(a,m)} ) \,mod\,\frac{m}{(a,m)} $

POJ 2115 就是求当$a=C$,$b=B-A$,$m=2^k$的最小解

#include "iostream"
using namespace std;
typedef long long LL;
void ext_gcd(LL a, LL b, LL &s, LL& x, LL& y) {
    LL res;
    if (!b){x = 1; y = 0; s = a;}
    else {
        ext_gcd(b, a%b, s, y, x);
        y -= x*(a/b);
    }
}
LL mod_line(LL a, LL b, LL m) {
    LL x, y, d;ext_gcd(a, m, d, x, y);
    if (b%d) return -1;
    LL e = x*(b/d)%(m/d) + (m/d);
    return e%(m/d);
}
int main(int argc, char const *argv[])
{
    LL a,b,c,d;
    while (cin >> a >> b >> c >> d) {
        if (!a&&!b&&!c&&!d) break;
        LL ans = mod_line(c, b-a, (LL)1 << d);
        if (ans == -1) cout << "FOREVER\n";
        else cout << ans << endl;
    }
    return 0;
}



 

时间: 2024-10-14 07:40:05

POJ 2115C Looooops[一元线性同余方程]的相关文章

POJ 1061 - 青蛙的约会 - [exgcd求解一元线性同余方程]

先上干货: 定理1: 如果d = gcd(a,b),则必能找到正的或负的整数k和l,使ax + by = d. (参考exgcd:http://www.cnblogs.com/dilthey/p/6804137.html) 定理2: 一元线性同余方程ax ≡ n (mod b) 有解,当且仅当gcd(a,b)|n. 也就是说,解出了ax+by=gcd(a,b),就相当于解出了ax≡n(mod b) (而且只要满足gcd(a,b)|n,就一定有解) 定理3: 若gcd(a,b) = 1,则方程ax

求解一元线性同余方程组模版

解法:直接上模版. 扩展欧几里德的模版: typedef long long LL; LL ex_gcd(LL a,LL b,LL &x,LL &y) { if(b==0) { x=1; y=0; return a; } LL d=ex_gcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return d; } 求解一元线性同余方程组模版: LL solve(LL n) { LL a1,r1,a2,r2; LL a,b,c,r,x,y; bool ifhave=

HDU1573:X问题(解一元线性同余方程组)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1573 题目解析;HDU就是坑,就是因为n,m定义成了__int64就WAY,改成int就A了,无语. 这题就是求解一元线性同余方程组的解满组小于正整数n的数目.最小正整数的解为X=(X*(c/d)%t+t)%t;  X=a1*X+r1;其中X为扩展欧几里得解出来的特解,这m个方程组的循环区间为lcm(a1,a2,a3...am),所以答案为(n-X)/lcm+1; #include <iostream>

HDU1573 X问题【一元线性同余方程组】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1573 题目大意: 求在小于等于N的正整数中有多少个X满足:X mod a[0] = b[0], X mod a[1] = b[1], X mod a[2] = b[2], -, X mod a[i] = b[i], - (0 < a[i] <= 10). 思路: 先求出数组b[]中所有数的最小公倍数lcm,再求解出该一元线性同余方程组在lcm范围内的解为a,题目要 求解x是小于等于N的正整数,则

HDU3579:Hello Kiki(解一元线性同余方程组)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3579 题目解析:求一元线性同余方程组的最小解X,需要注意的是如果X等于0,需要加上方程组通解的整数区间lcm(a1,a2,a3,...an). 别的就没什么注意的了. #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h&

POJ2891 Strange Way to Express Integers【一元线性同余方程组】

题目链接: http://poj.org/problem?id=2891 题目大意: 选择k个不同的正整数a1.a2.-.ak,对于某个整数m分别对ai求余对应整数ri,如果 适当选择a1.a2.-.ak,那么整数m可由整数对组合(ai,ri)唯一确定. 若已知a1.a2.-.ak以及m,很容易确定所有的整数对(ai,ri),但是题目是已知a1. a2.-.ak以及所有的整数对(ai,ri),求出对应的非负整数m的值. 思路: 题目可以转换为给定一系列的一元线性方程 x ≡ r1( mod a1

HDU3579 Hello Kiki【一元线性同余方程组】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3579 题目大意: Kiki有X个硬币,她用不同的方式数了N次,每次她把硬币分成大小相等的组,记录每次一组硬币 的个数Mi和数完最后剩余的硬币数Ai.那么问题来了:总共有多少枚硬币? 思路: 典型的一元线性同余方程组X = Ai(mod Mi)求解.题目要求输出最小正整数解,则如果求得同余 方程组的解为0,那么答案就是所有Mi的最小公倍数. AC代码: #include<iostream> #in

POJ2115 C Looooops(线性同余方程)

无符号k位数溢出就相当于mod 2k,然后设循环x次A等于B,就可以列出方程: $$ Cx+A \equiv B \pmod {2^k} $$ $$ Cx \equiv B-A \pmod {2^k} $$ 最后就用扩展欧几里得算法求出这个线性同余方程的最小非负整数解. 1 #include<cstdio> 2 #include<cstring> 3 #define mod(x,y) (((x)%(y)+(y))%(y)) 4 #define ll long long 5 ll e

POJ 2115-C Looooops(基础一元线性同余方程)

题意: 对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次才会结束. 若在有限次内结束,则输出循环次数. 否则输出FOREVER 思路: 易列出同余方程: x*C+y*2^k = B-A用拓展gcd求解即可 //148K 0MS C++ 808B #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespac