1. 程式人生 > >hdu 4704 Sum (整數和分解+快速冪+費馬小定理降冪)

hdu 4704 Sum (整數和分解+快速冪+費馬小定理降冪)

題意:

給n(1<n<),求(s1+s2+s3+...+sn)mod(1e9+7)。其中si表示n由i個數相加而成的種數,如n=4,則s1=1,s2=3。                         (全題文末)

知識點:

整數n有種和分解方法。

費馬小定理:p是質數,若p不能整除a,則 a^(p-1) ≡1(mod p)。可利用費馬小定理降素數冪。

    當m為素數,(m必須是素數才能用費馬小定理)

      a=2時。(a=2只是題中條件,a可以為其他值)

     mod m =   *      //  k=

                   =                                 //==1為費馬小定理的應用

例如,設p=7, n=32, 求2^32≡x(mod p)的值

由於p是素數,所以一定存在2^6≡1(mod p)

2^32%p=(2^[(6*5)+2])%p

=[2^(6*5)*2^2]%p

=[(2^(6*5)%p)*(2^2%p)]%p    //(a*b)%m=[(a%m)*(b%m)]%m;

=[1*(2^2%p)]%p                  //2^(6*5)%p為對費馬小定理的應用

=2^2%p;

題解:

題目相當於求n的分解種數。例如,n=x1+x2+x3+..xk是一種分解,把xi看成由xi個1組成,同理n即為n個1組成。

題目也就是給n個1分組的方法數(這不是類似於組合數學的小球間隔板問題嗎)。每兩個1之間是否放隔板,有放和不放兩種選擇,一共n-1個可選擇間隔。so 總方法數為 。

由於n太大,不好處理啊。

指數太大,發現m=1e9+7為素數,則可用費馬小定理(a^(p-1))≡1(mod p))降冪。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int mod=1e9+7,N=1e5+5;
char a[N];
 
LL quick_mod(LL a,LL p)          //快速冪 (快速冪利用了二分思想和秦九昭演算法)
{
    LL ans=1;
    while(p)
    {
        if(p&1)
            ans=ans*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return ans;
}
 
int main()
{
    while(~scanf("%s",a))
    {
        int len=strlen(a);
        LL ans=0;
        for(int i=0;i<len;i++)
        {
            ans=(ans*10+a[i]-'0')%(mod-1);
        }
        ans=(ans-1+mod-1)%(mod-1);
        printf("%lld\n",quick_mod(2,ans));
    }
    return 0;
}

這道題還可以找迴圈結。

發現 2^500000003 = 1 = 2^0,所以n=(n-1)%500000003,所以 2^(n - 1) = 2^((n-1)%(mod -1))%mod; (mod-1=500000003)

Sum

Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

Sample Input

2

Sample Output

2

Hint

 1. For N = 2, S(1) = S(2) = 1. 2. The input file consists of multiple test cases. 

#include <bits/stdc++.h>
using namespace std;
long long M=1e9+7;


/*
題意:
	S(k)是x1+x2+..+xk=N的組合數
	求(S(1)+S(2)+..+S(N))mod 10^9的個數

題解: 
	注:在這裡1+2+1=4 和 1+1+2=4 屬於不同的方案數 
	1.求解S(k):  將整數m拆分為n個數字的有序拆分方案數為C(m-1,n-1)(這個是二項式係數)
		隔板法理解:
				把N分成一份的分法數為C(1,n-1), 

				把N分成兩份的分法數為C(2,n-1),
				
				把N分成三份的分法數為C(3,n-1),
				
				.... ,
				
				把N分成N份的分法數為C(n-1,n-1)。 
		
	2.求解S(1)+S(2)+..+S(n) = C(0,n-1)+C(1,n-2)+..+C(n-1,n-1) = 2^n-1   為什麼這樣?二項式定理 可以理解成2^(n-1)=(1+1)^(n-1)展開
	 
	3.變成求解2^(n-1) mod 10^9, 

	4. 因為N比較大,所以可以用費馬小定理(假如a,p互質,則a^(p-1)%p == 1恆成立)化簡下
		我們可以把n分解。變成t個(p-1)+m。也就是(t*(p-1)+m) %p。
		費馬小定理:2^(p-1)%p正好等於1,那就是t個1,乘上一個數沒有影響,所以只剩下2^m % p
		所以可以寫成:2^n%p=2^(n%(p-1))%p	 而 n%(p-1)=m

*/

long long quick(long long a,long long n)
{
	long long sum=1;
	while(n)
	{
		if(n&1)
		{
			sum=(sum*a)%M;
		}
		a=a*a%M;
		n>>=1;
	}
	return sum;
}

int main()
{
	long long n;
	char s[100005];
	while(cin>>s)
	{
		n=0;
		int len=strlen(s);
		for(int i=0;i<len;i++)
			n=(n*10+s[i]-'0')%(M-1);
		cout<<quick(2,n-1)<<endl;
	 }
	return 0;
}