牛客网 NC207427 直线 高精度

1. 题目描述

1.1. Limit

Time Limit: C/C++ 1秒,其他语言2秒

Memory Limit: C/C++ 262144K,其他语言524288K

1.2. Problem Description

平面上存在 nn 条直线。请问 nn 条直线在平面上最多存在多少交点。

1.3. Input

输入数据的第一行是t,表示数据的组数 t<100(t < 100), 接下来每组数据输入一个 n1n1e15n(1 \le n \le 1e15)

1.4. Output

对于每组输入样例,打印 nn 条直线最多有多少个交点

1.5. Sample Input

2
1
2

1.6. Sample Output

0
1

1.7. Source

牛客网 NC207427 直线

2. 解读

i+1i + 1 条线最多能和前 ii 条线都相交,产生 ii 个新的交点。

所以最终结果为

n(n1)2 \frac{n(n-1)}{2}

但由于 nn 的数据范围很大 1n1e15(1 \le n \le 1e15),所以要使用高精度进行计算。高精度模板参考自百度百科-高精度算法

3. 代码

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct Wint : vector<int> //用标准库vector做基类,完美解决位数问题,同时更易于实现
{
    //将低精度转高精度的初始化,可以自动被编译器调用
    //因此无需单独写高精度数和低精度数的运算函数,十分方便
    Wint(int n = 0) //默认初始化为0,但0的保存形式为空
    {
        push_back(n);
        check();
    }
    Wint& check() //在各类运算中经常用到的进位小函数,不妨内置
    {
        while (!empty() && !back())
            pop_back(); //去除最高位可能存在的0
        if (empty())
            return *this;
        for (size_t i = 1; i < size(); ++i) //处理进位
        {
            (*this)[i] += (*this)[i - 1] / 10;
            (*this)[i - 1] %= 10;
        }

        while (back() >= 10) {
            push_back(back() / 10);
            (*this)[size() - 2] %= 10;
        }
        return *this; //为使用方便,将进位后的自身返回引用
    }
};
//输入输出
istream& operator>>(istream& is, Wint& n)
{
    string s;
    is >> s;
    n.clear();
    for (int i = s.size() - 1; i >= 0; --i)
        n.push_back(s[i] - '0');
    return is;
}
ostream& operator<<(ostream& os, const Wint& n)
{
    if (n.empty())
        os << 0;
    for (int i = n.size() - 1; i >= 0; --i)
        os << n[i];
    return os;
}

//比较,只需要写两个,其他的直接代入即可
//常量引用当参数,避免拷贝更高效
bool operator!=(const Wint& a, const Wint& b)
{
    if (a.size() != b.size())
        return 1;
    for (int i = a.size() - 1; i >= 0; --i)
        if (a[i] != b[i])
            return 1;
    return 0;
}
bool operator==(const Wint& a, const Wint& b)
{
    return !(a != b);
}
bool operator<(const Wint& a, const Wint& b)
{
    if (a.size() != b.size())
        return a.size() < b.size();
    for (int i = a.size() - 1; i >= 0; --i)
        if (a[i] != b[i])
            return a[i] < b[i];
    return 0;
}
bool operator>(const Wint& a, const Wint& b)
{
    return b < a;
}
bool operator<=(const Wint& a, const Wint& b)
{
    return !(a > b);
}
bool operator>=(const Wint& a, const Wint& b)
{
    return !(a < b);
}
//加法,先实现+=,这样更简洁高效
Wint& operator+=(Wint& a, const Wint& b)
{
    if (a.size() < b.size())
        a.resize(b.size());
    for (size_t i = 0; i != b.size(); ++i)
        a[i] += b[i];
    return a.check();
}
Wint operator+(Wint a, const Wint& b)
{
    return a += b;
}

//减法,返回差的绝对值,由于后面有交换,故参数不用引用
Wint& operator-=(Wint& a, Wint b)
{
    if (a < b)
        swap(a, b);
    for (size_t i = 0; i != b.size(); a[i] -= b[i], ++i)
        if (a[i] < b[i]) //需要借位
        {
            size_t j = i + 1;
            while (!a[j])
                ++j;
            while (j > i) {
                --a[j];
                a[--j] += 10;
            }
        }
    return a.check();
}
Wint operator-(Wint a, const Wint& b)
{
    return a -= b;
}
//乘法不能先实现*=,原因自己想
Wint operator*(const Wint& a, const Wint& b)
{
    Wint n;
    n.assign(a.size() + b.size() - 1, 0);
    for (size_t i = 0; i != a.size(); ++i)
        for (size_t j = 0; j != b.size(); ++j)
            n[i + j] += a[i] * b[j];
    return n.check();
}
Wint& operator*=(Wint& a, const Wint& b)
{
    return a = a * b;
}
//除法和取模先实现一个带余除法函数
Wint divmod(Wint& a, const Wint& b)
{
    Wint ans;
    for (int t = a.size() - b.size(); a >= b; --t) {
        Wint d;
        d.assign(t + 1, 0);
        d.back() = 1;
        Wint c = b * d;
        while (a >= c) {
            a -= c;
            ans += d;
        }
    }
    return ans;
}
Wint operator/(Wint a, const Wint& b)
{
    return divmod(a, b);
}
Wint& operator/=(Wint& a, const Wint& b)
{
    return a = a / b;
}
Wint& operator%=(Wint& a, const Wint& b)
{
    divmod(a, b);
    return a;
}
Wint operator%(Wint a, const Wint& b)
{
    return a %= b;
}
//顺手实现一个快速幂,可以看到和普通快速幂几乎无异
Wint pow(const Wint& n, const Wint& k)
{
    if (k.empty())
        return 1;
    if (k == 2)
        return n * n;
    if (k.back() % 2)
        return n * pow(n, k - 1);
    return pow(pow(n, k / 2), 2);
}

int main()
{
    int t;
    Wint n;
    cin >> t;
    while (t--) {
        cin >> n;
        cout << n * (n - 1) / 2 << endl;
    }
}


联系邮箱[email protected]

CSDNhttps://me.csdn.net/qq_41729780

知乎https://zhuanlan.zhihu.com/c_1225417532351741952

公众号复杂网络与机器学习

欢迎关注/转载,有问题欢迎通过邮箱交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章