[费马小定理+组合数] hdu 4704

题目

S(k)是x1+x2+…+xk=N的组合数 (重复的组合数,即:1+2+1=4 和 1+1+2=4 属于不同的方案数)
求(S(1)+S(2)+…+S(N))mod 10^9的个数
在这里插入图片描述
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4704

思路

求解S(k): 将整数m拆分为n个数字的有序拆分方案数为C(m-1,n-1)
隔板法理解:

                把N分成一份的分法数为C(0,n-1), 

                把N分成两份的分法数为C(1,n-1),

                把N分成三份的分法数为C(2,n-1),

                .... ,

                把N分成N份的分法数为C(n-1,n-1)。 

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
由于n上限非常大,可以用费马小定理(若a,p互质,a^(p-1)%p=1)化简。
可以把n-1分解成t个p-1,剩余m,则2^(n-1)%mod可化为 2^m%mod

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<iomanip>
#include<list>
#include<bitset>
#include<sstream>
#include<fstream>
#include<complex>
#include<algorithm>
#if __cplusplus >= 201103L
#include <unordered_map>
#include <unordered_set>
#endif
#define ll long long
#define int long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
int quick_pow(int a,int b){
	int res=1;
	while(b){
		if(b&1){
			res=(res*a)%mod;
		}
		a=(a*a)%mod;
		b>>=1;
		}
	return res;
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	string s;
	while(cin>>s){
	int ss=s.size(); 
	int res=0;
	for(int i=0;i<ss;i++){
		res=(res*10+s[i]-'0')%(mod-1);
	}
//	res=(res-1+mod-1)%(mod-1);
//	cout<<res<<endl;
	cout<<quick_pow(2,res-1)<<endl;}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kosf_/article/details/107374346
今日推荐