数论-裴蜀定理-POJ2115-C-Loop

数论-裴蜀定理-POJ2115-C-Loop

题目:

对于 C 语言的循环语句,形如:

for (variable = A; variable != B; variable += C)
statement;
请问在 k 位存储系统中循环几次才会结束。

若在有限次内结束,则输出循环次数。否则输出死循环。

输入格式
多组数据,每组数据一行四个整数 A,B,C,k。

读入以 0 0 0 0 结束。

输出格式
若在有限次内结束,则输出循环次数。

否则输出 FOREVER。

数据范围
1≤k≤32,
0≤A,B,C<2k
输入样例:
3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0
输出样例:
0
2
32766
FOREVER

题意:

k 位 系 统 中 二 进 制 的 值 仅 保 留 后 k 位 , 即 需 要 将 值 对 2 k 取 模 。 k位系统中二进制的值仅保留后k位,即需要将值对2^k取模。 kk2k

列 出 关 系 式 : ( A + C x ) m o d   2 k = B 等 价 于 A + C x + 2 k y = B , 即 求 方 程 C x + 2 k y = B − A 的 解 ( x , y ) 。 列出关系式:(A+Cx)mod\ 2^k=B等价于A+Cx+2^ky=B,即求方程Cx+2^ky=B-A的解(x,y)。 (A+Cx)mod 2k=BA+Cx+2ky=BCx+2ky=BA(x,y)

① 、 判 断 a x + b y = d 是 否 有 整 数 解 即 判 断 g c d ( a , b ) 是 否 为 d 的 因 子 。 ①、判断ax+by=d是否有整数解即判断gcd(a,b)是否为d的因子。 ax+by=dgcd(a,b)d

② 、 要 求 x 的 最 小 正 值 , 通 过 a x + b y = d 的 通 解 形 式 { x = x 0 + k b ′ y = y 0 − k a ′ , 其 中 a ′ = a d , b ′ = b d 。 ②、要求x的最小正值,通过ax+by=d的通解形式\begin{cases}x=x_0+kb'\\y=y_0-ka'\end{cases},其中a'=\frac{a}{d},b'=\frac{b}{d}。 xax+by=d{x=x0+kby=y0ka,a=da,b=db
将 x 对 b ′ 取 模 , 最 小 正 值 即 ( x 0 % b ′ + b ′ ) % b ′ 。 将x对b'取模,最小正值即(x_0\%b'+b')\%b'。 xb(x0%b+b)%b

解题步骤:

  1. 扩 展 欧 几 里 得 算 法 求 方 程 C x + 2 k y = g c d ( C , 2 k ) 的 解 , 若 g c d ( C , 2 k ) 不 是 B − A 的 因 子 , 则 死 循 环 。 扩展欧几里得算法求方程Cx+2^ky=gcd(C,2^k)的解,若gcd(C,2^k)不是B-A的因子,则死循环。 Cx+2ky=gcd(C,2k)gcd(C,2k)BA
  2. 接 着 将 求 得 的 x 扩 大 B − A g c d ( C , 2 k ) 倍 。 接着将求得的x扩大\frac{B-A}{gcd(C,2^k)}倍。 xgcd(C,2k)BA
  3. 最 后 根 据 公 式 求 最 小 值 ( x % b ′ + b ′ ) % b ′ 。 最后根据公式求最小值(x\%b'+b')\%b'。 (x%b+b)%b

代码:

#include<cstdio>
#include<iostream>
#define ll long long

using namespace std;

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    ll d=exgcd(b,a%b,x,y);
    ll tmp=y;
    y=x-(a/b)*y;
    x=tmp;
    return d;
}

int main()
{
    ll A,B,C,k;
    while(~scanf("%lld%lld%lld%lld",&A,&B,&C,&k),A||B||C||k)  
    {
        ll x,y;
        ll b=1ll<<k;   ///1要转换为ll
        int d=exgcd(C,b,x,y);
        if((B-A)%d!=0) cout<<"FOREVER"<<endl;
        else
        {
            int tmp=((B-A)/d);
            x*=tmp;
            b/=d;  ///b要更新为b'
            x=(x%b+b)%b;
            cout<<x<<endl;
        }
    }

    return 0 ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值