51nod 算法马拉松 集合计数

列出等式之后 发现是二元一次不定式 求正整数解 然而并不会求解 枚举肯定超时 经过一番搜索 发现是扩展欧几里德  然后现学现卖了一下  

然而边界问题 涉及到四个实数化整 并求交集 需要考虑的太多 一时考虑不清楚 决定暴力枚举 然后只过了一半数据 只好又回头处理边界问题  静下心来 仔细一思考 边界问题也并不是那么难处理


System Message  (命题人)
基准时间限制:1 秒 空间限制:131072 KB 分值: 20

给出N个固定集合{1,N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数。

提示:

对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个。


Input
第1行:1个整数T(1<=T<=50000),表示有多少组测试数据。
第2 - T+1行:每行三个整数N,A,B(1<=N,A,B<=2147483647)
OutPut
对于每组测试数据输出一个数表示满足条件的集合的数量,占一行。
Input示例
2
5 2 4
10 2 3
Output示例
1
2


#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <iterator>
#include <cmath>
#include <deque>
#include <stack>
#include <cctype>
#include <iomanip>
using namespace std;

typedef long long ll;
typedef long double ld;

const int N = 1100;
const int INF = 0xfffffff;
const double EPS = 1e-8;
const ll MOD = 1e9 + 7;
const ld PI = acos (-1.0);

#define INFL 0x7fffffffffffffffLL
#define met(a, b) memset(a, b, sizeof(a))
#define put(a) cout << setiosflags(ios::fixed) << setprecision(a)

ll gcd (ll a, ll b)
{
    return b ? gcd (b, a % b) : a;
}
ll extgcd (ll a, ll b, ll &x, ll &y)
{
    ll d = a;
    if (b != 0)
    {
        d = extgcd (b, a % b, y, x);
        y -= (a / b) * x;
    }
    else
        x = 1, y = 0;
    return d;
}


int main ()
{
    int t;
    cin >> t;
    while (t--)
    {
        ll n, a, b, d, x, y;
        cin >> n >> a >> b;

        d = gcd (a, b);

        if ((n + 1) % d != 0)
        {
            cout << 0 << endl;
            continue;
        }

        extgcd (a, b, x, y);

        ll x1, y1;
        double k1, k2, k3, k4;
        ll tk1, tk2, tk3, tk4;
        x1 = x * (n + 1) / d;
        y1 = y * (n + 1) / d;

        k1 = 1.0 * d * (1 - x1) / b;
        tk1 = (ll)k1;
        if (x1 + b / d * tk1 < 1) tk1++;

        k2 = 1.0 * d * (n + 1 - x1) / b;
        tk2 = (ll)k2;

        k3 = 1.0 * d * (y1 - 1) / a;
        tk3 = (ll)k3;
        if (y1 - a / d * tk3 < 1) tk3--;

        k4 = 1.0 * d * (y1 - n - 1) / a;
        tk4 = (ll)k4;


        if (tk1 - tk3 > 0 || tk4 - tk2 > 0)
            cout << 0 << endl;

        else
        {
            ll xx = max (tk1, tk4);
            ll yy = min (tk2, tk3);

            if (yy < xx) cout << 0 << endl;
            else
                cout << yy - xx + 1 << endl;
        }

    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值