题目描述:
As you may already know, Eddy likes to walk around. Especially, he likes to walk in a number line called “Infinite line”. Actually, it’s exactly a line with infinite length!
Eddy is at number 0 and starts to walk around. Since Eddy is a little drunk(just finished his work, make sense), he will not walk in a fixed length. Instead, he will independently uniformly randomly walk in an integer length between 1 and K. That is, he will walk for 1 unit of length in a probability of 1 k \frac{1}{k} k1,…, K units in 1 k \frac{1}{k} k1. If he currently stands on number i and walk for j unit of length, he will end up on number i+j.
Since Eddy is drunk, he will walk around infinitely. You, somehow, notice this weird thing and start wondering whether will Eddy ever step on the number N. However, you don’t want to wait for such stupid thing. You would like to compute the probability that Eddy would ever step on number N.
输入描述:
The first line of input contains an integers T.
Following T lines each contains two space-separated integers Ki and Ni.
If Ni=-1,Ni is a number approaching infinity.
1≤T≤10
1≤Ki≤1021
-1≤Ni≤1018
输出描述:
For each i, output one line containing a number representing the probability.
You should output the number module 10^9+7(1000000007).
Suppose the probability is
P
Q
\frac{P}{Q}
QP, the desired output will be P×Q-1 mod 109+7
示例1:
输入
3
1 0
2 1
3 -1
输出
1
500000004
500000004
题解:
• Math, Linear Recurrence, Dynamic Programming
• Math, Linear Recurrence, Dynamic Programming
prob[i] = (prob[i-1] + prob[i-2] + … + prob[i-k]) / k
prob[0] = 1
prob[i < 0] = 0
prob[x -> \infinity] = 2 / (k + 1)
• Math, Linear Recurrence, Dynamic Programming
prob[i] = (prob[i-1] + prob[i-2] + … + prob[i-k]) / k
Results in an O(NK) solutions. Clearly TLE
• Math, Linear Recurrence, Dynamic Programming
Solving Linear Recurrence faster? Matrix Multiplication!
Results in an O(K^3 \lg N). Still TLE…
• Math, Linear Recurrence, Dynamic Programming
Solving Linear Recurrence faster? Matrix Multiplication!
Actually, we can solve LR in O(K^2 \lg N)!
• Math, Linear Recurrence, Dynamic Programming
Solving LR in O(K^2 \lg N)!
Core Idea: How to represent dp[n] from dp[0], dp[1], …, dp[k]
If we can do that, we can compute dp[n] in O(K)
• Math, Linear Recurrence, Dynamic Programming
Solving LR in O(K^2 \lg N)!
Core Idea: How to represent dp[n] from dp[0], dp[1], …, dp[k]
We can represent dp[n] from dp[n-1], dp[n-2], … dp[n-k] so as dp[n-1] from dp[n-2], dp[n-3], …, dp[n-k-1]
Then, we can represent dp[n] from dp[n-2], dp[n-3], …, dp[n-k-1]
• Math, Linear Recurrence, Dynamic Programming
Solving LR in O(K^2 \lg N)! Core Idea: How to represent dp[n] from dp[0], dp[1], …, dp[k]
dp[n] = W_1 dp[n-1] + W_2 dp[n-2] + … + W_k dp[n-k] dp[n-1] = W_1 dp[n-2] + W_2 dp[n-3] + … + W_k dp[n-k-1] -> dp[n] = V_1 dp[n-2] + V_2 dp[n-3] + … + V_k dp[n-k-1] If we do this till first k terms, it’s in O(NK)! We need to be faster!!
• Math, Linear Recurrence, Dynamic Programming
Solving LR in O(K^2 \lg N)! Core Idea: How to represent dp[n] from dp[0], dp[1], …, dp[k] We need to be faster!! -> Do multiple steps at once!(Expand them all)
• Math, Linear Recurrence, Dynamic Programming
Solving LR in O(K^2 \lg N)! Core Idea: How to represent dp[n] from dp[0], dp[1], …, dp[k] We can expand the parameters twice in O(k^2) now.
Then, we can compute the required parameters in O(K^2 \lg N)
Bonus: Exists an O(K \lg K \lg N) algorithm to solve LR
代码:
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 2048;
constexpr int mod = 1e9 + 7;
constexpr int MOD = 1e9 + 7;
typedef long long LL;
typedef long long ll;
inline int add(int a, int b) {
a += b;
return a >= mod ? a - mod : a;
}
inline int sub(int a, int b) {
a -= b;
return a < 0 ? a + mod : a;
}
inline int mul(LL a, int b) {
a *= b;
return a >= mod ? a % mod : a;
}
inline int mpow(int a, int b) {
int r = 1;
while (b) {
if (b & 1) {
r = mul(r, a);
}
a = mul(a, a);
b >>= 1;
}
return r;
}
inline int inv(int x) {
return mpow(x, mod - 2);
}
LL n , m, ik;
constexpr int MAX_N = 1024;
ll dp[MAX_N<<1];
inline void pre_dp() {
LL bdr = min(n + n , m);
dp[0] = 1;
for(ll i = 1; i <= bdr; i++) {
dp[i] = 0LL;
for (int j = 1 ; j <= n; ++j) {
if (i - j < 0 ) break;
dp[i] = (dp[i] + dp[i - j] * ik % MOD) % MOD;
}
}
}
inline vector<ll> mul(vector<ll>& v1 , vector<ll>& v2) {
int sz1 = (int)v1.size();
int sz2 = (int)v2.size();
vector<ll> _v(n + n);
for(int i = 0; i < n + n; i++) _v[i] = 0;
// expand
for(int i = 0; i < sz1; i++) {
for(int j = 0; j < sz2; j++) {
(_v[i + j + 1] += v1[i] * v2[j] % MOD) %= MOD;
}
}
// shrink
for(int i = 0; i < n; i++) {
for(int j = 1; j <= n; j++) {
(_v[i + j] += _v[i] * ik) %= MOD;
}
}
for(int i = 0; i < n; i++) _v[i] = _v[i + n];
_v.resize(n);
return _v;
}
vector<ll> I , A;
inline ll solve() {
pre_dp();
if(m <= n + n) return dp[m];
I.resize(n);
A.resize(n);
for(int i = 0; i < n; i++) {
I[i] = ik;
A[i] = ik;
}
// dp[m] = /Sum_{i=0}^{n-1} A_i * dp[m - i - 1]
ll dlt = (m - n) / n;
ll rdlt = dlt * n;
while(dlt) {
if(dlt & 1LL) I = mul(I , A);
A = mul(A , A);
dlt >>= 1LL;
}
ll ans = 0;
for(int i = 0; i < n; i++) {
(ans += I[i] * dp[m - i - 1 - rdlt] % MOD) %= MOD;
}
return ans;
}
int main() {
LL n_, k_;
int t; cin >> t; while (t--) {
cin >> k_ >> n_;
n = k_;
m = n_;
ik = inv(k_);
ll ans;
if (n_ == -1) {
ans = mul(2, inv(k_ + 1));
} else {
ans = solve();
}
printf("%lld\n", ans);
}
}
更多问题,更详细题解可关注牛客竞赛区,一个刷题、比赛、分享的社区。
传送门:https://ac.nowcoder.com/acm/contest/discuss