SWJTUOJ-2397 A Easy Counting Problem

来源:互联网 发布:绝知此事要躬行意思 编辑:程序博客网 时间:2024/05/18 00:48

A Easy Counting Problem

发布时间: 2017年6月10日 19:41   最后更新: 2017年6月10日 19:44   时间限制: 1000ms   内存限制: 128M

Megumin喜欢计数问题。

一天,Megumin在一个圆上画了n个点,并用线段把任意两点都连起来,她很想知道此时圆内有多少个交点。

然而,Megumin发现,即使圆上的点数n相同,圆内的交点数也不一定相同。

她很好奇,当圆上有n个点时,圆内最多有多少个交点呢?

由于结果很大,Megumin只需要知道结果对1e9+7取模的值就可以了,你能告诉她吗?

第一行是一个整数T(T<=50),表示数据组数.
接下来是T组数据.
每组数据是一个整数n(1<=n<=1e9),表示圆上有n个点.

对于每组数据输出一个整数,表示此时圆内最多的交点数,结果对1e9+7取模

14
1
思路:为了尽可能让交点最多,所以需要满足圆上任意四个点都能够构成一个四边形,又因为四边形的对角线相交后会产生一个交点,当任意四边形两对角线产生的交点不重合时有最多的交点数,所以由数学知识可得假设圆上有n个点,那么交点个数最多可以有C(n,4)个,但是当n特别大时数据一定会溢出,题目中要求输出对1e9+7取模的结果,就可以使用乘法逆元来解决,先对乘法逆元进行打表,然后每计算一步就取模一次则可以防止溢出。

对乘法逆元进行打表:

void init(){    inv[1] = 1;    for (int i = 2; i <= 110000; i++)    {        inv[i] = (MOD - MOD / i) * inv[MOD%i] % MOD;    }}
使用乘法逆元计算组合数对目标数取模的结果,这里因为题目要求所以限制了m=4,稍加修改即可以求取其他组合数对目标数取模的值:

ll Calcul(int n, int m = 4){    c[0] = 1;    for (int i = 1; i <= m; i++)    {        c[i] = c[i - 1] * ((n - i + 1) % MOD*inv[i] % MOD) % MOD;        c[i] = c[i] % MOD;    }    return c[m];}
AC代码:

#include <bits/stdc++.h>using namespace std;#define MOD 1000000007#define inf 0x7f7f7f7f#define ll long long#define ull unsigned long longconst int MAXN = 1e5+5;ll inv[110000], c[5];void init(){    inv[1] = 1;    for (int i = 2; i <= 110000; i++)    {        inv[i] = (MOD - MOD / i) * inv[MOD%i] % MOD;    }}ll Calcul(int n, int m = 4){    c[0] = 1;    for (int i = 1; i <= m; i++)    {        c[i] = c[i - 1] * ((n - i + 1) % MOD*inv[i] % MOD) % MOD;        c[i] = c[i] % MOD;    }    return c[m];}int main(){    memset(inv, 0, sizeof(inv));    init();    int t;    cin >> t;    while (t--)    {        memset(c, 0, sizeof(c));        int n;        cin >> n;        cout << Calcul(n) << endl;    }    return 0;}