洛谷 AT249 紅茶(Tea) - 模拟、二分

洛谷 AT249 紅茶(Tea)

题目链接:洛谷 AT249 紅茶(Tea)

算法标签: 模拟二分

题目

题目描述

一天,\(kagamiz\) 一边喝红茶,一边尝试解答如下的问题:

当由两个正整数所组成的正整数组以如下方式排列时, \((m,n)\)是这个数列里的第几组?

\((1,1),(2,1),(1,2),(3,1),(2,2),(1,3),(4,1),(3,2),(2,3),(1,4),(5,1),…\)

这个问题对他来说太简单了,所以他更深入地考虑了以下这个问题:

当上述数列中的 \(i\) 个组为\((a_i,b_i)\),第 \(j\) 个组为\((a_j,b_j)\)时, \((a_i+a_j,b_i+b_j)\)是这个数列里的第几组?

你的任务就是帮助他解答这个问题。

输入格式

输入仅一行,为两个正整数 \(i,j\)

输出格式

输出为一个正整数,表示当上述数列中的第\(i\)个组为\((a_i,b_i)\), 第\(j\)个组为\((a_j,b_j)\)时, \((a_i+a_j,b_i+b_j)\)是这个数列里的第几组。

输入输出样例

输入 #1

1 1

输出 #1

5

输入 #2

3 2

输出 #2

13

输入 #3

114 514

输出 #3

1155

说明/提示

数据范围:

  • \(i≥1,1≤j≤10^8\),且\(i,j\)均为正整数。
  • \(i,j\) 可能相等。

题解:

首先这道题我们要看所给出的数对:

\((1,1),(2,1),(1,2),(3,1),(2,2),(1,3),(4,1),(3,2),(2,3),(1,4),(5,1),…\)

我们可以发现,和为\(n\)的数对共有\(n - 1\)对,所以可以根据这个规律来统计所询问为第几组。

之后继续观察,在每一个合为\(n\)的数对组中,第一位是从 \(n - 1\)\(1\) 递减的,而第二位则正好相反,从 \(1\)\(n - 1\)递增,这个可以统计为第几行(将所有和相等的数对看做一行)的第几个。

同样由于本题的数据范围 \(1 ≤ j ≤ 10^8\) ,显然我们暴力进行查询和求和是很受限制的(没有测过),所以我们选择使用等差数列求和二分答案的方式进行求解,具体代码实现如下:

long long getsum(ll q) // 等差数列求和
{
    return 1ll * ((1 + q) * q) / 2;
}
void find(long long q) // 二分查找答案
{
    ll l = 1, r = N + 1, mid;
    while(l < r)
    {
        mid = (l + r) >> 1;
        if (getsum(mid) >= q)
            r = mid;
        else 
            l = mid + 1;
    }
    yy = q - getsum(l - 1);
    xx = l - yy + 1;
}

AC代码

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 1e8 + 10;
typedef long long ll;
int xx, yy;
long long getsum(ll q)
{
    return 1ll * ((1 + q) * q) / 2;
}
void find(long long q)
{
    ll l = 1, r = N + 1, mid;
    while(l < r)
    {
        mid = (l + r) >> 1;
        if (getsum(mid) >= q)
            r = mid;
        else 
            l = mid + 1;
    }
    yy = q - getsum(l - 1);
    xx = l - yy + 1;
}
int main()
{
    ll x, y;
    scanf("%lld%lld", &x, &y);
    find(x);
    ll ax = xx, ay = yy;
    find(y);
    ll bx = xx, by = yy;
    ll qx = ax + bx, qy = ay + by;
    ll pos = qx + qy - 1;
    pos = getsum(pos - 1) + qy;
    printf("%lld\n", pos);
    return 0;
}
posted @ 2019-11-12 21:59  筱柒_Littleseven  阅读(111)  评论(0编辑  收藏  举报