题意: 给定
n
n
n,
S
k
S_k
Sk为
x
1
+
x
2
+
.
.
.
+
x
k
=
n
x_1+x_2+...+x_k=n
x1+x2+...+xk=n的正整数解的方案数,求
(
S
1
+
S
2
+
.
.
.
S
k
)
m
o
d
(
1
0
9
+
7
)
(S_1+S_2+...S_k)\bmod (10^9+7)
(S1+S2+...Sk)mod(109+7)
数据范围:
1
<
n
<
1
0
2000
1<n<10^{2000}
1<n<102000
注意:当
k
=
2
,
n
=
4
k=2,n=4
k=2,n=4,
x
1
=
1
,
x
2
=
3
x_1=1,x_2=3
x1=1,x2=3和
x
1
=
3
,
x
2
=
1
x_1=3,x_2=1
x1=3,x2=1是两种方案。
题解: 一步步分析,
S
1
S_1
S1为
x
1
=
n
x_1=n
x1=n的方案数,自然为
1
1
1,
S
2
S_2
S2为
x
1
+
x
2
=
n
x_1+x_2=n
x1+x2=n,则有
n
−
1
n-1
n−1z种方案。可以想到用隔板法来求解每个方案,即
n
n
n个数构成了
n
−
1
n-1
n−1个空,有
k
k
k个解就要插入
k
−
1
k-1
k−1个隔板。那么答案即为
C
n
−
1
0
+
C
n
−
1
1
+
.
.
.
+
C
n
−
1
n
−
2
+
C
n
−
1
n
−
1
=
2
n
−
1
C_{n-1}^0+C_{n-1}^1+...+C_{n-1}^{n-2}+C_{n-1}^{n-1}=2^{n-1}
Cn−10+Cn−11+...+Cn−1n−2+Cn−1n−1=2n−1。
证明即二项式定理:
(
x
+
y
)
n
−
1
=
C
n
−
1
0
x
0
y
n
−
1
+
C
n
−
1
1
x
1
y
n
−
2
+
.
.
.
+
C
n
−
1
n
−
2
x
n
−
2
y
1
+
C
n
−
1
n
−
1
x
n
−
1
y
0
(x+y)^{n-1}=C_{n-1}^0x^0y^{n-1}+C_{n-1}^1x^1y^{n-2}+...+C_{n-1}^{n-2}x^{n-2}y^{1}+C_{n-1}^{n-1}x^{n-1}y^0
(x+y)n−1=Cn−10x0yn−1+Cn−11x1yn−2+...+Cn−1n−2xn−2y1+Cn−1n−1xn−1y0
令
x
=
y
=
1
x=y=1
x=y=1即可。
本题的 n n n过大,所以无法直接使用快速幂。
- 根据费马小定理
a
p
−
1
≡
1
(
m
o
d
p
)
,
(
a
,
p
)
=
1
a^{p-1}\equiv1\pmod{p},(a,p)=1
ap−1≡1(modp),(a,p)=1
所以 2 n − 1 = 2 k × ( p − 1 ) + r 2^{n-1}=2^{k\times{(p-1)}+r} 2n−1=2k×(p−1)+r, 2 p − 1 m o d p = 1 2^{p-1}\bmod p=1 2p−1modp=1
故 2 n − 1 m o d p = 2 r m o d p 2^{n-1}\bmod p=2^{r}\bmod p 2n−1modp=2rmodp - 欧拉降幂:
2
n
−
1
≡
2
(
n
−
1
)
%
φ
(
p
)
+
φ
(
p
)
2^{n-1}\equiv2^{(n-1)\%φ(p)+φ(p)}
2n−1≡2(n−1)%φ(p)+φ(p)
注意 − 1 -1 −1必须最后减去,因为大数边计算边取模,先处理 − 1 -1 −1是错误的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 100010;
char s[N];
int qp(int a, int b) {
int ans = 1;
while(b) {
if(b & 1) ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ans;
}
int main()
{
while(~scanf("%s", s)){
int mi = 0;
for(int i = 0; s[i]; i++) mi = (mi * 10ll + s[i] - '0') % (mod - 1);
mi = (mi - 1 + mod - 1) % (mod - 1);
int res = qp(2, mi);
printf("%d\n", res);
}
return 0;
}