@Wannafly summer camp Day2 B: Utawarerumono (数学公式, 扩展欧几里得)

算术是为数不多的会让久远感到棘手的事情。通常她会找哈克帮忙,但是哈克已经被她派去买东西了。于是她向你寻求帮助。

给出一个关于变量x,y的不定方程ax+by=c,显然这个方程可能有多个整数解。久远想知道如果有解,使得p2*x2+p1*x+q2*y2+q1*y最小的一组整数解是什么。为了方便,你只需要输出p2*x2+p1*x+q2*y2+q1*y的最小值。

 

输入

第一行三个空格隔开的整数a,b,c(0≤a,b,c≤105)。
第二行两个空格隔开的整数p1,p2(1≤p1,p2≤105)。
第三行两个空格隔开的整数q1,q2(1≤q1,q2≤105)。

 

输出

如果方程无整数解,输出"Kuon"。
如果有整数解,输出p2*x^2+p1*x+q2*y^2+q1*y的最小值。

 

样例输入

2 2 1
1 1
1 1

 

样例输出

Kuon

ax + by = c

p2*x^2+p1*x+q2*y^2+q1*y

扩展欧几里得 求得  ax + by = c  一组特解. 

然后 利用 下式, 判断 在 对称轴出 附近取得 最小值.

推导 对称轴 问题.

过程如下:

y=\dfrac {c-ax}{b};将y带入方程可得:

p_{2}x^{2}+p_{1}x+q_{2}\dfrac {c^{2}+a^{2}x^{2}-2acx}{b^{2}}+q_{1}\dfrac {c-ax}{b}

=\left( p_{2}+\dfrac {a^{2}q_{2}}{b^{2}}\right) x^{2}+\left( p_{1}-\dfrac {2acq_{2}}{b^{2}}-\dfrac {aq_{1}}{b}\right) x+\dfrac {q_{2}c^{2}}{b^{2}}+\dfrac {q_{1}c}{b}

由抛物线的性质可知:方程p_{2}x^{2}+p_{1}x+q_{2}y^{2}+q_{1}y的最小值在对称轴附近

由上式化简可知,抛物线的对称轴为:\dfrac {\dfrac {q_{1}a}{b}+\dfrac {2ac}{b^{2}}-p_{1}}{2( p_{2}+\dfrac {a^{2}}{b^{2}}q_{2})}

 

 

[代码]

 

#include <bits/stdc++.h>
#include <stdio.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
  
typedef long long ll;
const int maxn = 1e5+10;
const int mod =1e9+7;
const int inf = 0x3f3f3f3f;
using namespace std;
  
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1;y=0;return a;}
    ll ans=exgcd(b,a%b,x,y);
    ll temp=x;   x=y;  y=temp-a/b*y;
    return ans;
}
  
  
ll getMin(ll a,ll b)
{
    ll ab = -1.0*b/(2.0*a);
    ll minn = (1ll<<63)-1;
    for(ll x = ab - 1000;x <= ab + 1000;x++)
        minn = min(minn,a*x*x + b*x);
    return minn;
}
  
int main(int argc, char const *argv[])
{
    /* code */
  
    ll a,b,c,p1,p2,q1,q2;
    //cout<<exgcd(2,4,a,b)<<endl;
    scanf("%lld%lld%lld",&a,&b,&c);
    scanf("%lld%lld",&p1,&p2);
    scanf("%lld%lld",&q1,&q2);
  
    if(a == 0 && b == 0){
        if(c == 0)
            printf("%lld\n",getMin(p2,p1) + getMin(q2,q1));
        else
            puts("Kuon");
    }
    else if(a == 0)
    {
        ll y = c/b;
        if(c % b == 0)
            printf("%lld\n",q2*y*y+q1*y + getMin(p2,p1));
        else
            puts("Kuon");
    }
    else if(b == 0)
    {
        ll x = c/a;
        if(c % a == 0)
            printf("%lld\n",p2*x*x+p1*x + getMin(q2,q1));
        else
            puts("Kuon");
    }
    else
    {
        ll x0,y0;
        ll gcd = exgcd(a,b,x0,y0);
        if(c % gcd != 0)
            puts("Kuon");
        else{
            x0 = x0*c/gcd;
            y0 = y0*c/gcd;
            //x = x0 +(b/gcd)*t;
            double A,B;
            B = 1.0*p1 - 2.0*q2*a*c/(b*b) - 1.0*q1*a/b;
            A = 1.0*p2 + 1.0*q2*a*a/(b*b);
            ll ab = -B/(2.0*A);
  
            ll t = (ab - x0*1.0)/(b/gcd);
            ll minn = (1ll<<63)-1;
            for(ll j = t - 1;j <= t + 1;j++)
            {
                ll x = x0 + (b/gcd)*j,y = y0 - (a/gcd)*j;
                minn = min(minn,p2*x*x+p1*x+q2*y*y+q1*y);
            }       
            printf("%lld\n",minn);
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值