1. 程式人生 > >(割圓問題與費馬小定理)牛客多校8 G題

(割圓問題與費馬小定理)牛客多校8 G題

連結:https://www.nowcoder.com/acm/contest/146/G
來源:牛客網
 

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 131072K,其他語言262144K
64bit IO Format: %lld

題目描述

Niuniu likes mathematics. He also likes drawing pictures. One day, he was trying to draw a regular polygon with n vertices. He connected every pair of the vertices by a straight line as well. He counted the number of regions inside the polygon after he completed his picture. He was wondering how to calculate the number of regions without the picture. Can you calculate the number of regions modulo 1000000007? It is guaranteed that n is odd.

輸入描述:

The only line contains one odd number n(3 ≤ n ≤ 1000000000), which is the number of vertices.

輸出描述:

Print a single line with one number, which is the answer modulo 1000000007.

示例1

輸入

複製

3

輸出

複製

1

示例2

輸入

複製

5

輸出

複製

11

備註:

 

The following picture shows the picture which is drawn by Niuniu when n=5. Note that no three diagonals share a point when n is odd.

題目的大意是給出一個n,表示正n邊型。讓每個頂點兩兩相連求一共分割了多少塊領域。

此題是圖論裡的割圓問題,割圓問題既在圓的的邊界上選取n個點並且兩兩相連,求分割了多少塊領域,與此題相似。割圓問題的公式如下圖:

 

 

 

 

 

 

 

 

 

 

 

 

這個公式實際上包括了幾條弦分割的圓的領域,可以看出n個點就有n條弦從而對圓有n個區域的劃分。我們求得是內部多邊形的分割數量所以要減去弦的分割。

那麼最終的公式應該是:1+C(n,2)+C(n,4)-n;

這裡強烈推薦3B1B的一個視訊,詳細的解釋了割圓問題。https://www.bilibili.com/video/av19849697

不過呢,其中還有一個問題,那就是求組合數的時候有除法運算,直接取餘是不行的,所以我們要用費馬小定理來求分母的逆元。雖然我之前寫過費馬小定理的部落格但是還是在這裡再寫一遍。

費馬小定理:若p是素數那麼a^p=a(mod p)   

推論 :a^(p-1)=1(mod p)   我們要求的是逆元,逆元就是某個數的倒數(粗俗的理解)  a的逆元就是1/a。那麼推論的式子裡兩邊都除以a右邊就是1/a了,左邊就是a的逆元,既a^(p-2)。

以下是程式碼:

#include<stdio.h>

unsigned long long mod=1000000007;
/*快速冪*/
unsigned long long qpow(unsigned long long b,unsigned long long m){
	unsigned long long sum=1;
	
	while(m){
		if(m%2) sum=sum*b%mod;
		m=m/2;
		b=b*b%mod;
	}
	return sum;
}
int main(){
	unsigned long long n;
	while(scanf("%lld",&n)!=EOF){
        /*求C(n,2)的逆元*/
		unsigned long long fm1=qpow(2,mod-2)%mod;
        /*求C(n,4)的逆元*/
		unsigned long long fm2=qpow(24,mod-2)%mod,n1,n2;
        /*求C(n,2)*/
		n1=n*(n-1)%mod;
        /*求C(n,4)*/
		n2=n*(n-1)%mod;
		n2=n2*(n-2)%mod;
		n2=n2*(n-3)%mod;
        
		n1=n1*fm1%mod;
		n2=n2*fm2%mod;
        
		n=(mod+n1+n2+1-n)%mod;
		printf("%llu\n",n);
	}
	
	return 0;
}