HDU - 1098 - Ignatius's puzzle - ax+by=c

http://acm.hdu.edu.cn/showproblem.php?pid=1098

其实一开始猜测只要验证x=1的时候就行了,但是不知道怎么证明。
题解表示用数学归纳法,假设f(x)成立,证明f(x+1)成立需要什么条件。

代入之后发现有很多二项式系数,导致他们都是65的倍数,剩下的恰好就是 f(x) 和 18+ka 。

那么只需要找到最小的a使得 18+ka是65的倍数。

题解说,毕竟65毕竟小,可以枚举a。因为a+65与a的对65的余数是一样的,所以只要枚举0到64就可以了。

我的想法是用扩展欧几里得求这个的解。

首先由裴蜀定理 ax+by=c 有解,当且仅当gcd(a,b)|c

那么 18+ka=65t 即 -ka+65t=18 求a的最小非负整数解。套方程的模板。

忘记写解方程的返回值导致返回一个任意值,有毒。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//扩展欧几里得算法:返回 g=gcd(a,b) ,以及对应的等式 ax+by=g 的解
ll exgcd(ll a,ll b,ll &x,ll &y) {
    if(!a&&!b)
        return -1;
    if(!b) {
        x=1,y=0;
        return a;
    }
    ll d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}

bool Liner_qu(ll a, ll b, ll c, ll &x, ll &y) {
    if(a==0) {
        if(b==0) {
            if(c==0) {
                x=0;
                y=0;
                return true;
            } else {
                return false;
            }
        }
        if(c%b==0) {
            x=0;
            y=c/b;
            return true;
            //0x+by=c
        } else
            return false;
    }
    if(b==0) {
        if(c%a==0) {
            x=c/a;
            y=0;
            return true;
            //ax+0y=c
        } else {
            return false;
        }
    }
    ll g=__gcd(a,b);
    if(c%g){
        return false;
    }
    //裴蜀定理

    ll k=c/g;
    exgcd(a,b,x,y);
    //ax+by=g的解
    x *= k; // 任意一解
    y *= k;

    ll tx = x;

    x %= b; //最小解
    if(x<0)
        x += abs(b); //最小非负整数解
    k=(tx-x)/b;
    y += k*a; //对应的y的解
    return true;
}


ll F(int k) {
    int a;
    {
        if(k%5==0||k%13==0)
            return -1;
        else {
            a=1;
            while((k*a+18)%65!=0) {
                a++;
            }
            return a;
        }
    }
}

ll G(int k) {
    ll a,b,c,x,y;
    a=-k;
    b=65;
    c=18;

    bool flag=Liner_qu(a,b,c,x,y);

    if(flag) {
        return x;
    } else {
        return -1;
    }
}

int main() {
    int k;
    while(cin>>k) {
        ll a,b,c,x,y;
        a=-k;
        b=65;
        c=18;

        bool flag=Liner_qu(a,b,c,x,y);

        if(flag){
            cout<<x<<endl;
        }
        else{
            cout<<"no"<<endl;
        }
    }

    /*for(int k=1; k<=10000; k++) {
        ll s1=F(k);
        ll s2=G(k);
        if(s1!=s2) {
            cout<<"k="<<k<<endl;
            cout<<s1<<endl<<s2<<endl;
        }
    }*/
}

转载于:https://www.cnblogs.com/Yinku/p/10739667.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值