Time Limit: C/C++ 1秒,其他语言2秒
Memory Limit: C/C++ 262144K,其他语言524288K
平面上存在 n n n 条直线。请问 n n n 条直线在平面上最多存在多少交点。
输入数据的第一行是t,表示数据的组数 ( t < 100 ) (t < 100) (t<100), 接下来每组数据输入一个 n ( 1 ≤ n ≤ 1 e 15 ) n(1 \le n \le 1e15) n(1≤n≤1e15)
对于每组输入样例,打印 n n n 条直线最多有多少个交点
2
1
2
0
1
牛客网 NC207427 直线
第 i + 1 i + 1 i+1 条线最多能和前 i i i 条线都相交,产生 i i i 个新的交点。
所以最终结果为
n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1)
但由于 n n n 的数据范围很大 ( 1 ≤ n ≤ 1 e 15 ) (1 \le n \le 1e15) (1≤n≤1e15),所以要使用高精度进行计算。高精度模板参考自百度百科-高精度算法。
#include
#include
#include
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]
CSDN:https://me.csdn.net/qq_41729780
知乎:https://zhuanlan.zhihu.com/c_1225417532351741952
公众号:复杂网络与机器学习
欢迎关注/转载,有问题欢迎通过邮箱交流。