1. 程式人生 > >費馬小定理 + 快速冪 Give Candies

費馬小定理 + 快速冪 Give Candies

There are NN children in kindergarten. Miss Li bought them NN candies. To make the process more interesting, Miss Li comes up with the rule: All the children line up according to their student number (1...N)(1...N), and each time a child is invited, Miss Li randomly gives him some candies (at least one). The process goes on until there is no candy. Miss Li wants to know how many possible different distribution results are there.

Input

The first line contains an integer TT, the number of test case.

The next TT lines, each contains an integer NN.

1 \le T \le 1001≤T≤100

1 \le N \le 10^{100000}1≤N≤10^100000

Output

For each test case output the number of possible results (mod 1000000007).

樣例輸入複製

1
4

樣例輸出複製

8

題目來源

解題思路:

可知有n個糖和無限個學生,並且分到的每個學生至少分一個糖果。

那麼不難想到,第一個學生必定要分到第一個糖果,第二個糖果可以給當前的學生或者下一個學生,有兩種分法,第三個學生同樣可以分給當前學生或下一個學生,有兩種分法......

即總共有:1*2^(n-1)種分法

所以該題目要求的就是2^(n-1)。( 實際是:2^(n-1)%mod  )

但是問題是n比較大,是無法直接計算的,那麼我們怎麼才能快速計算出2^(n-1)%mod呢?

此處我們需要用到費馬小定理。

-------------------------------------------------費馬小定理簡述-----------------------------------------------------

文章來自於百度百科,有部分改動。

引理1.
  若a,b,c為任意3個整數,m為正整數,且(m,c)=1,則當a·c≡b·c(mod m)時,有a≡b(mod m)。
  證明:a·c≡b·c(mod m)可得ac–bc≡0(mod m)可得(a-b)·c≡0(mod m)。因為(m,c)=1即m,c互質,c可以約去,a– b≡0(mod m)可得a≡b(mod m)。 [1]

引理2.
  設m是一個整數且m>1,b是一個整數且(m,b)=1。如果a[1],a[2],a[3],a[4],…a[m]是模m的一個完全剩餘系,則b·a[1],b·a[2],b·a[3],b·a[4],…b·a[m]也構成模m的一個完全剩餘系。
  證明:若存在2個整數b·a[i]和b·a[j]同餘即b·a[i]≡b·a[j](mod m)..(i>=1 && j>=1),根據引理1則有a[i]≡a[j](mod m)。根據完全剩餘系的整數可知這是不可能的,因此不存在2個整數b·a[i]和b·a[j]同餘。

所以b·a[1],b·a[2],b·a[3],b·a[4],…b·a[m]構成模m的一個完全剩餘系。

構造素數  的剩餘系(此處百度百科上為完全剩餘系,而我認為不對 ┑( ̄Д  ̄)┍ )

因為  ,由引理2可得

也是p的一個剩餘系(百度百科此處也為完全剩餘系)。由剩餘系的性質,

即 

易知  ,同餘式兩邊可約去  ,得到

這樣就證明了費馬小定理。

-----------------------------------------------------------------------------------------------------------------------

由費馬小定理可知

即a^(p-1)與1關於p同餘。

即a^(p-1)%p=1;

我們可以把一個比較大的a^n拆成如下形式:

a^n=a^(p-1)*a^(p-1)*a^(p-1)...*a^x;

a^n%p=(a^(p-1)%p)*(a^(p-1)%p)*(a^(p-1)%p)*....*(a^x%p);//x為將n按照一份p-1的方式分,分剩下的。

由上述推導我們可知:a^n%p=(1)*(1)*(1)*....*(a^x%p);

即:a^n%p=a^(n%(p-1))%p;

那麼我們首先需要求n%(p-1);

對於這樣大的一個n我們可以採用邊輸入邊求餘的方式得到n%p-1;

String s;
long long ans=0;
for(int i=0;i!=s.size();i++)
{
	ans*=10;
	ans+=(s[i]-'0');
	ans%=(p-1);
}

可知n%(p-1)仍然是一個很大的數字,畢竟mod=1000000007;

那麼我們需要用快速冪的方法快速求出a^(n%(p-1))%p;

最終程式碼為:

#include<bits/stdc++.h> 
using namespace std;

const long long p=1000000007;
int T;

int main()
{
	scanf("%d",&T);
	for(int t=0;t!=T;t++)
	{
		string s;
		cin>>s;
		long long ans=0;
		for(int i=0;i!=s.size();i++)
		{
			ans*=10;
			ans+=(s[i]-'0');
			ans%=(p-1);
		}
		ans--;
		long long base=2,answer=1;
		while(ans)
		{
			if(ans&1)answer=answer*base%p;
			base=base*base%p;
			ans>>=1;
		}
		printf("%lld\n",answer);
	}
    return 0;
}