组合数学+费马小定理化简
首先是隔板的思想,s(i) 的意思可以解读为把n个木条排成一排,分成 i 份 ,那么我们根据隔板法,在n个木条就有n-1个空位可以加入隔板(因为每个数是正整数),那么s(i) = C( n-1 , i -1)
那么s(1) + s(2) + ... + s(n) = 2 ^ (n-1) 答案即为 2 ^ (n-1) % mod
但是因为n特别大,可以用费马小定理进行优化
2 ^ n % m = 2 ^ ( (n % (m-1) ) + [n / (m - 1)] * m-1 ) % m( 其中 [ ] 代表取整,因为一个数可以分解成 num = q * mod + p,)
那么同余定理可知, 2 ^ ( (n % (m-1) ) + [n / (m - 1)] * m-1 ) % m = ( ( 2 ^ (n % (m-1) ) ) % m * (2 ^ k) ^ (m-1) ) % m ) % m
因为m在这里是1e9 + 7 是一个质数,那么 (2 ^ k) ^ (m-1) ) % m = 1
最终可以得到 2 ^ n % m = 2 ^ (n % (m-1) ) % m
n % m-1 就在我们的可计算范围内了
那么我们先计算 n % m-1 然后通过快速幂计算2 ^ (n % (m - 1) ) % m
代码如下 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
char s[maxn];
LL qpow(LL a,LL b,LL mod){
LL ans = 1,base = a % mod;
while(b){
if (b & 1) ans = ans * base % mod;
base = base * base % mod;
b >>= 1;
}
return a % mod;
}
int main(){
while(scanf("%s",s) == 1){
LL num = 0;
int len = (int)strlen(s);
for (int i=0; i<len; i++)
num = (num*10 + s[i]-'0')%(mod-1);
if (num == 0){
printf("%lld\n",qpow(2, mod-2, mod));
}else{
printf("%lld\n",qpow(2, num-1, mod));
}
}
return 0;
}