1352 集合计数 扩展欧几里德算法

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1352

题目的本意就是要求

ax+by=n+1

a * x + b * y = c,在x >= 1和y >= 1的条件下的解的个数。

①、等于0的情况是:

1、方程无解,

2、最小的解就是(1. 1),大家都是1倍,如果比c还大,那就是0

3、设最小的解是x1,如果c - a * x1 < b,那也不行。也就是b不够一倍了。

 

其他的:(设x1是最小的正整数解)

通解就是x0 = x1 + b / (abgcd) * k,(k >= 0)

然后带入去a * x + b * y = c,同样c - a * x1也是要大于等于b才行,因为起码都要一倍。

然后解出的k,就是答案。包括上0,所以是k + 1

 

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
LL exgcd(LL a, LL mod, LL &x, LL &y) {
    //求解a关于mod的逆元     ★:当且仅当a和mod互质才有用
    if (mod == 0) {
        x = 1;
        y = 0;
        return a;//保留基本功能,返回最大公约数
    }
    LL g = exgcd(mod, a % mod, x, y);
    LL t = x;    //这里根据mod==0  return回来后,
    x = y;  //x,y是最新的值x2,y2,改变一下,这样赋值就是为了x1=y2
    y = t - (a / mod) * y;    // y1=x2(变成了t)-[a/mod]y2;
    return g;            //保留基本功能,返回最大公约数
}

bool get_min_number (LL a, LL b, LL c, LL &x, LL &y) { //得到a*x+b*y=c的最小整数解
    LL abGCD = __gcd(a, b);
    if (c % abGCD != 0) return false; //不能整除GCD的话,此方程无解
    a /= abGCD;
    b /= abGCD;
    c /= abGCD;
    LL tx, ty;
    exgcd(a, b, tx, ty); //先得到a*x+b*y=1的解,注意这个时候gcd(a,b)=1
    x = tx * c;
    y = ty * c;  //同时乘上c,c是约简了的。得到了一组a*x + b*y = c的解。
    LL haveSignB = b;
    if (b < 0) b = -b;     //避免mod负数啊,模负数没问题,模了负数后+负数就GG
    x = (x % b + b) % b;  //最小解
    if (x == 0) x = b; //避免x = 0不是"正"整数  不要用这个,溢出
    y = (c - a * x); // haveSignB;
    return true; //true代表可以
}

void work() {
    LL a, b, c;
    cin >> c >> a >> b;
    c++;
    if (c % __gcd(a, b) != 0 || a + b > c) {
        cout << 0 << endl;
        return;
    }
    LL x1, y1;
    get_min_number(a, b, c, x1, y1);
    LL t = c - b - a * x1;
    if (c - x1 * a < b) {
//        cout << t << endl;
//        cout << c << " " << a << " " << b << endl;
//        while(1);
        cout << 0 << endl;
        return;
    }
    t /= a / __gcd(a, b) * b;
    cout << t + 1 << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    IOS;
    int t;
    cin >> t;
    while (t--) work();
    return 0;
}
View Code

 

posted on 2017-02-07 22:16  stupid_one  阅读(221)  评论(0编辑  收藏  举报

导航