牛客網 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

公衆號複雜網絡與機器學習

歡迎關注/轉載,有問題歡迎通過郵箱交流。

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