题解 | Eddy Walker 2-2019牛客暑期多校训练营第二场B题

题目描述:
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值