湘潭市大学四月月赛C题A+B(扩展欧几里得定理)

湘潭大学四月月赛C题A+B(扩展欧几里得定理)

A+B

Accepted : 8   Submit : 77
Time Limit : 1000 MS   Memory Limit : 65536 KB 

题目描述

给你三个整数a,b,n。问有多少种只包含a,b的不同序列,使得这个序列的和为n。 例如a=2,b=3,n=7,那么有一种序列:(2+2+3=7,2+3+2=7,3+2+2=7)这三种看作相同,算一种。 例如a=3,b=3,n=6,那么只有一种序列:3+3=6。 例如a=4,b=5,n=7,那么不管a和b怎么排都不会等于7,那么就只有0种序列。

输入

多个样例,每个样例占一行,包括3个整数a,b,n。(0< a,b,n <10^9).直到文件结束。

输出

每个样例输出一行,一个整数,为a,b所能排出的序列数。

样例输入

2 3 7
3 3 6
4 5 7

样例输出

1
1
0


题目意思就不说了,中文题目。

看到这个就想到了扩展欧几里得,不过手搓,没写出来,然后就找了以前自己写的扩展欧几里得模板。

没学过扩展欧几里得算法的可以看下http://blog.sina.com.cn/s/blog_61c7e64d0100kwna.html 科普下。

利用扩展欧几里得可以解出ax+by=1的一个解,
现在的x,y是ax+by=1的一个解,
x=x*s,y=y*s;   同时扩大s倍,
        现在的xy是ax+by=s的一个解
因为ax+by=s,所以a(x+nb)+b(y-na)=s也是可行解
进而可以把ax+by=s通解找到。
由于这个题目要使得解都是正数或0,(0也可以,这点是大坑。。。要不是晓东当时问了一句c题是不是a和b不一定要有,当时都不知道问题所在。)还有就是a==b需要特判。


AC代码:
//a和b不一定要有,fuck!!!
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

//不用int64就可以A的
__int64 exgcd(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    __int64 g=exgcd(b,a%b,x,y);
    __int64 temp=x;
    x=y;
    y=temp-(a/b)*y;
    return g;
}

__int64 gcd(__int64 m,__int64 n)
{
    while(n)
    {
        __int64 tmp=m%n;
        m=n;
        n=tmp;
    }
    return m;
}

__int64 mi(__int64 m,__int64 n)
{
    if(m>n) return n;
    return m;
}

__int64 ma(__int64 m,__int64 n)
{
    if(m>n) return m;
    return n;
}

int main()
{
    __int64 a,b,s,d;
    while(~scanf("%I64d%I64d%I64d",&a,&b,&s))
    {
        __int64 x,y;
        d=gcd(a,b);
        if(s%d!=0)
        {
            puts("0");
            continue;
        }
        else if(a+b>s)
        {
            puts("0");
            continue;
        }
        else if(a==b)
        {
            if(s%a==0)
                puts("1");
            else puts("0");
            continue;
        }

        a=a/d,b=b/d,s=s/d;
        __int64 tt=exgcd(a,b,x,y);

        //现在的x,y是ax+by=1的一个解
        x=x*s,y=y*s;
        //现在的xy是ax+by=s的一个解

        __int64 cnt=0;
        //__int64 s1,s2;

        //根据x,y的值来判断到底有多少可行解
        //因为ax+by=s,所以a(x+nb)+b(y-na)=s也是可行解,所以直接找n的值使得x+nb与y-na都为正数或0即可

        //代码写搓了。。
        /*if(x<=0&&y>=0)  //okok
        {
            x=-x;
            if(x%b==0) s1=x/b;
            else s1=x/b+1;

            if(y%a==0) s2=y/a;
            else s2=y/a;
        }
        else if(y<=0&&x>=0)  //okok
        {
            y=-y;
            if(y%a==0) s1=y/a;
            else s1=y/a+1;

            if(x%b==0) s2=x/b;
            else s2=x/b;
        }
        else if(x>0&&y>0)  //ok
        {
            s1=-x/b;
            s2=x/b;
            s1=ma(s1,-y/a);
            s2=mi(s2,y/a);
        }
        else
        {
            puts("0");
            continue;
        }*/
        x=x%b;
        if(x<0) x+=b;
        y=(s-a*x)/b;   //解出a(x+nb)+b(y-na)=s,n=0时候的值

        if(y<0) cnt=0;
        else cnt=y/a+1;
        printf("%I64d\n",cnt);
    }
    return 0;
}

感谢cc_again......