ACM-ICPC 2018 焦作赛区网络预赛 G. Give Candies
题目
有 n 个小朋友, n 个糖果。从 1 号小朋友开始发糖,每次发任意数量(但不少于 1 个)。直到发完,或者没有糖。问最终有多少种发糖方式。(n < 1 0 100000 , m o d = 1 e 9 + 7 ) 10^{100000}, mod = 1e9 + 7) 10100000,mod=1e9+7)
分析
首先这就是个整数划分的问题,通过打表也可以看出来答案是 a n s = 2 n − 1 ans = 2^{n-1} ans=2n−1。
但是可以看到,n 很大,这里用大数存,再计算估计也不行。这个形式可以想到费马小定理。
a
p
−
1
≡
1
(
 
m
o
d
 
p
)
a^{p-1} \equiv 1(\bmod p)
ap−1≡1(modp)
2
n
=
2
k
∗
(
p
−
1
)
+
n
 
m
o
d
 
(
p
−
1
)
=
1
∗
1
∗
.
.
.
.
∗
2
n
 
m
o
d
 
(
p
−
1
)
=
2
n
 
m
o
d
 
(
p
−
1
)
(
 
m
o
d
 
p
)
2^{n} = 2^{k*(p-1) + n \bmod (p-1)} = 1 * 1 * .... * 2^{n \bmod (p-1)} = 2^{n \bmod (p-1)}(\bmod p)
2n=2k∗(p−1)+nmod(p−1)=1∗1∗....∗2nmod(p−1)=2nmod(p−1)(modp)
2
n
−
1
=
2
n
 
m
o
d
 
(
p
−
1
)
−
1
(
 
m
o
d
 
p
)
2^{n - 1} = 2^{n \bmod (p-1) - 1}(\bmod p)
2n−1=2nmod(p−1)−1(modp)
所以 n 降到 (p-1) 之内再计算即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define fuck(x) cout<<x<<endl
const int N = 2e5 + 10;
const ll mod = 1e9 + 7;
int t;
char num[N];
ll qpm(ll x, ll y){
ll ans = 1;
while(y){
if(y&1)
ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
int main(){
scanf("%d", &t);
while(t--){
scanf("%s", num);
int len = strlen(num);
ll ans = 0;
for(int i = 0; i < len; i++){
ans *= 10;
ans += (num[i] - '0');
ans %= (mod - 1);
}
printf("%lld\n", qpm(2, --ans));
}
return 0;
}