Counting regions
这道题呢,其实是一道组合数学的题,再加上欧拉公式。
题意:问边数为奇数的正多边形所有的顶点两两相连,直线所分割的区域数量为多少,答案对 1e9+7 1 e 9 + 7 取模。
我们会发现题目中的图形,除了顶点是不会有三线交于一点的。所以分割区域的区域数量就只取决于点的数量。
现在我们未知:
1.
1.
一共有多少条直线?
2.
2.
这些直线在正多边形内的交点有多少个?
答案 1 1 :我们都知道两点构成一线,所以我们可以构成的直线就是在个顶点中选两个顶点(顶点两两相连嘛,这样保证了不会有三线交于一点),一共有 C(n,2) C ( n , 2 ) 条。
答案 2 2 :观察题目中的图就会发现,正多边形上的任意四个顶点所连成的两条直线交于唯一的一点。所以我们又可以从组合数学的角度来求交点数量,即个交点。
接下来引入欧拉公式 V−E+F=2 V − E + F = 2 ,意思就是只要满足不会有三线交于一点的任意多边形都满足这个公式。( V V 代表点的数量,代表边的数量, F F 代表所分割的区域数量)
但是我们这里的边数还没有求,通过小数据我们可以找出规律:,即 E=C(n,2)+2×C(n,4) E = C ( n , 2 ) + 2 × C ( n , 4 ) 。
所以最后 F=E−V+1=C(n,2)+2×C(n,4)−(C(n,4)+n)+1 F = E − V + 1 = C ( n , 2 ) + 2 × C ( n , 4 ) − ( C ( n , 4 ) + n ) + 1 ,这里为什么只加一呢?因为我们去除了正多边形外面的区域。
先来一份暴力
import java.util.Scanner;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
BigInteger n = in.nextBigInteger();
BigInteger C_n_2 = n.multiply(n.subtract(BigInteger.ONE)).divide(BigInteger.ONE.add(BigInteger.ONE));
BigInteger C_n_4 = n.multiply(n.subtract(BigInteger.ONE)).multiply(n.subtract(new BigInteger("2"))).multiply(n.subtract((new BigInteger("3")))).divide(new BigInteger("24"));
BigInteger ans = C_n_2.add(C_n_4).subtract(n.subtract(BigInteger.ONE)).mod(new BigInteger(""+(int)(1E9+7)));
System.out.println(ans);
in.close();
}
}
再来一份优雅
/*
* V - E + F = 2
* F = E - V + 2
* */
#include<bits/stdc++.h>
typedef long long LL;
const LL mod = 1e9+7;
LL Pow(LL a,LL n)
{
LL ans = 1, res = a;
while(n)
{
if(n&1) ans = ans * res % mod;
res = res * res % mod;
n >>= 1;
}
return ans;
}
LL Inv(LL n)
{
return Pow(n,mod-2);
}
int main()
{
LL n;
std::cin>>n;
// C(n,2)%mod - C(n,4)%mod + 2%mod
LL E = n*(n-1)%mod*Inv(2);
LL V = n*(n-1)%mod*(n-2)%mod*(n-3)%mod*Inv(24)%mod;
LL ans = E+V-n+1;
std::cout<<ans%mod<<std::endl;
return 0;
}